From 31c962567fde0128a980463498e814063eb4ed11 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 7 Jun 2022 22:00:23 +0000 Subject: [PATCH 001/187] Bump jmespath from 1.4.0 to 1.6.1 Bumps [jmespath](https://github.com/trevorrowe/jmespath.rb) from 1.4.0 to 1.6.1. - [Release notes](https://github.com/trevorrowe/jmespath.rb/releases) - [Changelog](https://github.com/jmespath/jmespath.rb/blob/main/CHANGELOG.md) - [Commits](https://github.com/trevorrowe/jmespath.rb/compare/v1.4.0...v1.6.1) --- updated-dependencies: - dependency-name: jmespath dependency-type: indirect ... Signed-off-by: dependabot[bot] --- Gemfile.lock | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 345b4c1502..7284d17c67 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -140,7 +140,7 @@ GEM http-cookie (1.0.4) domain_name (~> 0.5) httpclient (2.8.3) - jmespath (1.4.0) + jmespath (1.6.1) json (2.5.1) jwt (2.2.3) memoist (0.16.2) @@ -201,6 +201,7 @@ GEM PLATFORMS x86_64-darwin-20 + x86_64-linux DEPENDENCIES fastlane From 4d8f24b73c4750962c38c977c5527344d83414b6 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 23 Jun 2022 11:11:33 +0100 Subject: [PATCH 002/187] updating fastlane dependencies --- Gemfile.lock | 121 +++++++++++++++++++++++++++------------------------ 1 file changed, 65 insertions(+), 56 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 7284d17c67..2ac9762eac 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,50 +1,53 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.3) + CFPropertyList (3.0.5) + rexml addressable (2.8.0) public_suffix (>= 2.0.2, < 5.0) artifactory (3.0.15) atomos (0.1.3) - aws-eventstream (1.1.1) - aws-partitions (1.479.0) - aws-sdk-core (3.117.0) + aws-eventstream (1.2.0) + aws-partitions (1.600.0) + aws-sdk-core (3.131.2) aws-eventstream (~> 1, >= 1.0.2) - aws-partitions (~> 1, >= 1.239.0) + aws-partitions (~> 1, >= 1.525.0) aws-sigv4 (~> 1.1) - jmespath (~> 1.0) - aws-sdk-kms (1.44.0) - aws-sdk-core (~> 3, >= 3.112.0) + jmespath (~> 1, >= 1.6.1) + aws-sdk-kms (1.57.0) + aws-sdk-core (~> 3, >= 3.127.0) aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.96.1) - aws-sdk-core (~> 3, >= 3.112.0) + aws-sdk-s3 (1.114.0) + aws-sdk-core (~> 3, >= 3.127.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.1) - aws-sigv4 (1.2.4) + aws-sigv4 (~> 1.4) + aws-sigv4 (1.5.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) - claide (1.0.3) + claide (1.1.0) colored (1.2) colored2 (3.1.2) commander (4.6.0) highline (~> 2.0.0) declarative (0.0.20) - digest-crc (0.6.3) + digest-crc (0.6.4) rake (>= 12.0.0, < 14.0.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) dotenv (2.7.6) - emoji_regex (3.2.2) - excon (0.85.0) - faraday (1.5.1) + emoji_regex (3.2.3) + excon (0.92.3) + faraday (1.10.0) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) - faraday-httpclient (~> 1.0.1) + faraday-httpclient (~> 1.0) + faraday-multipart (~> 1.0) faraday-net_http (~> 1.0) - faraday-net_http_persistent (~> 1.1) + faraday-net_http_persistent (~> 1.0) faraday-patron (~> 1.0) - multipart-post (>= 1.2, < 3) + faraday-rack (~> 1.0) + faraday-retry (~> 1.0) ruby2_keywords (>= 0.0.4) faraday-cookie_jar (0.0.7) faraday (>= 0.8.0) @@ -53,15 +56,19 @@ GEM faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) faraday-httpclient (1.0.1) + faraday-multipart (1.0.4) + multipart-post (~> 2) faraday-net_http (1.0.1) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) - faraday_middleware (1.0.0) + faraday-rack (1.0.0) + faraday-retry (1.0.3) + faraday_middleware (1.2.0) faraday (~> 1.0) - fastimage (2.2.4) - fastlane (2.187.0) + fastimage (2.2.6) + fastlane (2.206.2) CFPropertyList (>= 2.3, < 4.0.0) - addressable (>= 2.3, < 3.0.0) + addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) aws-sdk-s3 (~> 1.0) babosa (>= 1.0.3, < 2.0.0) @@ -76,7 +83,7 @@ GEM faraday_middleware (~> 1.0) fastimage (>= 2.1.0, < 3.0.0) gh_inspector (>= 1.1.2, < 2.0.0) - google-apis-androidpublisher_v3 (~> 0.1) + google-apis-androidpublisher_v3 (~> 0.3) google-apis-playcustomapp_v1 (~> 0.1) google-cloud-storage (~> 1.31) highline (~> 2.0) @@ -85,6 +92,7 @@ GEM mini_magick (>= 4.9.4, < 5.0.0) multipart-post (~> 2.0.0) naturally (~> 2.2) + optparse (~> 0.1.1) plist (>= 3.1.0, < 4.0.0) rubyzip (>= 2.0.0, < 3.0.0) security (= 0.1.3) @@ -98,9 +106,9 @@ GEM xcpretty (~> 0.3.0) xcpretty-travis-formatter (>= 0.0.3) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.8.0) - google-apis-core (>= 0.4, < 2.a) - google-apis-core (0.4.0) + google-apis-androidpublisher_v3 (0.22.0) + google-apis-core (>= 0.5, < 2.a) + google-apis-core (0.6.0) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -109,52 +117,53 @@ GEM retriable (>= 2.0, < 4.a) rexml webrick - google-apis-iamcredentials_v1 (0.6.0) - google-apis-core (>= 0.4, < 2.a) - google-apis-playcustomapp_v1 (0.5.0) - google-apis-core (>= 0.4, < 2.a) - google-apis-storage_v1 (0.6.0) - google-apis-core (>= 0.4, < 2.a) + google-apis-iamcredentials_v1 (0.12.0) + google-apis-core (>= 0.6, < 2.a) + google-apis-playcustomapp_v1 (0.9.0) + google-apis-core (>= 0.6, < 2.a) + google-apis-storage_v1 (0.15.0) + google-apis-core (>= 0.5, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) - google-cloud-env (1.5.0) - faraday (>= 0.17.3, < 2.0) - google-cloud-errors (1.1.0) - google-cloud-storage (1.34.1) - addressable (~> 2.5) + google-cloud-env (1.6.0) + faraday (>= 0.17.3, < 3.0) + google-cloud-errors (1.2.0) + google-cloud-storage (1.36.2) + addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) google-apis-storage_v1 (~> 0.1) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (0.16.2) - faraday (>= 0.17.3, < 2.0) + googleauth (1.1.3) + faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) - signet (~> 0.14) + signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.4) + http-cookie (1.0.5) domain_name (~> 0.5) httpclient (2.8.3) jmespath (1.6.1) - json (2.5.1) - jwt (2.2.3) + json (2.6.2) + jwt (2.4.1) memoist (0.16.2) mini_magick (4.11.0) - mini_mime (1.1.0) + mini_mime (1.1.2) multi_json (1.15.0) multipart-post (2.0.0) nanaimo (0.3.0) naturally (2.2.1) - os (1.1.1) + optparse (0.1.1) + os (1.1.4) plist (3.6.0) - public_suffix (4.0.6) + public_suffix (4.0.7) rake (13.0.6) - representable (3.1.1) + representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) @@ -164,9 +173,9 @@ GEM ruby2_keywords (0.0.5) rubyzip (2.3.2) security (0.1.3) - signet (0.15.0) - addressable (~> 2.3) - faraday (>= 0.17.3, < 2.0) + signet (0.16.1) + addressable (~> 2.8) + faraday (>= 0.17.5, < 3.0) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) simctl (1.6.8) @@ -175,7 +184,7 @@ GEM terminal-notifier (2.0.0) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) - trailblazer-option (0.1.1) + trailblazer-option (0.1.2) tty-cursor (0.7.1) tty-screen (0.8.1) tty-spinner (0.9.3) @@ -183,11 +192,11 @@ GEM uber (0.1.0) unf (0.1.4) unf_ext - unf_ext (0.0.7.7) - unicode-display_width (1.7.0) + unf_ext (0.0.8.2) + unicode-display_width (1.8.0) webrick (1.7.0) word_wrap (1.0.0) - xcodeproj (1.20.0) + xcodeproj (1.22.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) From b52171c1dcd792e6995725af567d71e9cee6c77b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 17 Aug 2022 16:55:33 +0200 Subject: [PATCH 003/187] Run `bundle update` again. --- Gemfile.lock | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index d4beadae81..276f4ae66a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -8,20 +8,20 @@ GEM artifactory (3.0.15) atomos (0.1.3) aws-eventstream (1.2.0) - aws-partitions (1.600.0) - aws-sdk-core (3.131.2) + aws-partitions (1.619.0) + aws-sdk-core (3.132.0) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.525.0) aws-sigv4 (~> 1.1) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.57.0) + aws-sdk-kms (1.58.0) aws-sdk-core (~> 3, >= 3.127.0) aws-sigv4 (~> 1.1) aws-sdk-s3 (1.114.0) aws-sdk-core (~> 3, >= 3.127.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.4) - aws-sigv4 (1.5.0) + aws-sigv4 (1.5.1) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) claide (1.1.0) @@ -53,10 +53,10 @@ GEM rake (>= 12.0.0, < 14.0.0) domain_name (0.5.20190701) unf (>= 0.0.5, < 1.0.0) - dotenv (2.7.6) + dotenv (2.8.1) emoji_regex (3.2.3) - excon (0.92.3) - faraday (1.10.0) + excon (0.92.4) + faraday (1.10.1) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -74,7 +74,7 @@ GEM faraday-em_http (1.0.0) faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) - faraday-http-cache (2.4.0) + faraday-http-cache (2.4.1) faraday (>= 0.8) faraday-httpclient (1.0.1) faraday-multipart (1.0.4) @@ -87,7 +87,7 @@ GEM faraday_middleware (1.2.0) faraday (~> 1.0) fastimage (2.2.6) - fastlane (2.206.2) + fastlane (2.209.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) @@ -129,9 +129,9 @@ GEM gh_inspector (1.1.3) git (1.11.0) rchardet (~> 1.8) - google-apis-androidpublisher_v3 (0.22.0) - google-apis-core (>= 0.5, < 2.a) - google-apis-core (0.6.0) + google-apis-androidpublisher_v3 (0.25.0) + google-apis-core (>= 0.7, < 2.a) + google-apis-core (0.7.0) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -140,27 +140,27 @@ GEM retriable (>= 2.0, < 4.a) rexml webrick - google-apis-iamcredentials_v1 (0.12.0) - google-apis-core (>= 0.6, < 2.a) - google-apis-playcustomapp_v1 (0.9.0) - google-apis-core (>= 0.6, < 2.a) - google-apis-storage_v1 (0.15.0) - google-apis-core (>= 0.5, < 2.a) + google-apis-iamcredentials_v1 (0.13.0) + google-apis-core (>= 0.7, < 2.a) + google-apis-playcustomapp_v1 (0.10.0) + google-apis-core (>= 0.7, < 2.a) + google-apis-storage_v1 (0.17.0) + google-apis-core (>= 0.7, < 2.a) google-cloud-core (1.6.0) google-cloud-env (~> 1.0) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) google-cloud-errors (1.2.0) - google-cloud-storage (1.36.2) + google-cloud-storage (1.38.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.1) + google-apis-storage_v1 (~> 0.17.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.1.3) + googleauth (1.2.0) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) memoist (~> 0.16) @@ -210,9 +210,9 @@ GEM addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) security (0.1.3) - signet (0.16.1) + signet (0.17.0) addressable (~> 2.8) - faraday (>= 0.17.5, < 3.0) + faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) multi_json (~> 1.10) simctl (1.6.8) From 1b3e099d7ce4d91cb6615bc65945fc6f8495507e Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 14 Sep 2022 10:08:13 +0100 Subject: [PATCH 004/187] adding first pass at unit testing documentation --- docs/unit_testing.md | 352 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 352 insertions(+) create mode 100644 docs/unit_testing.md diff --git a/docs/unit_testing.md b/docs/unit_testing.md new file mode 100644 index 0000000000..d879ba18e7 --- /dev/null +++ b/docs/unit_testing.md @@ -0,0 +1,352 @@ +# Table of Contents + + + +* [Overview](#project-conventions) + * [Best Practices](#best-practices) +* [Project Conventions](#project-conventions) + * [Setup](#setup) + * [Naming](#naming) + * [Format](#format) + * [Assertions](#assertions) + * [Constants](#constants) + * [Mocking](#mocking) + * [Fakes](#fakes) + * [Fixtures](#fixtures) +* [Examples](#examples) + * [Simple](#extensions-used-to-streamline-the-test-setup) + * [Fakes and Fixtures](#fakes-and-fixtures) + * [ViewModel](#viewmodel) + + + +## Overview + +Unit tests are a mechanism to validate our code executes the way we expect. They help to inform the design of our systems by requiring testability and +understanding, they describe the inner workings without relying on inline comments and protect from unexpected regressions. + +However, unit tests are not a magical solution to solve all our problems and come at a cost. Unreliable and hard to maintain tests often end up ignored, deleted +or worse, provide a false sense of security. + +### Best Practices + +Tests can be written in many ways, the main rule is to keep them simple and maintainable. Some ways to help achieve this are... + +- Break out logic into single units (following the Single Responsibility Principle) to reduce test complexity. +- Favour pure functions, avoiding mutable state. +- Prefer dependency injection to static calls to allow for simpler test setup. +- Write concise tests with a single function under test, clearly showing the inputs and expected output. +- Create separate test cases instead of changing parameters and grouping multiple assertions within a single test to help trace back failure causes (with the + exception of parameterised tests). +- Assert against entire models instead of subsets of properties to capture any possible changes within the test scope. +- Avoid invoking logic from production instances other than the class under test to guard from unrelated changes. +- Always inject `Dispatchers` and `Clock` instances and provide fake implementations for tests to avoid non deterministic results. + +## Project Conventions + +#### Setup + +- Test file and class name should be the class under test with the Test suffix, created in a `test` sourceset, with the same package name as the class under + test. +- Dependencies of the class are instantiated inline, junit will recreate the test class for each test run. +- A line break between the dependencies and class under test helps clarify the instance being tested. + +```kotlin + +class MyClassTest { + + private val fakeUppercaser = FakeUppercaser() + + // line break between the class under test and its dependencies + private val myClass = MyClass(fakeUppercaser.instance) +} + +``` + +#### Naming + +- Test names use the `Gherkin` format, `given, when, then`mapping to the input, logic under test and expected result. + - `given` - Uniqueness about the environment or dependencies in which the test case is running. _"given device is android 12 and supports dark mode"_ + - `when` - The action/function under test. _"when reading dark mode status"_ + - `then` - The expected result from the combination of _given_ and _when_. _"then returns dark mode enabled"_ +- Test names are written using kotlin back ticks to enable _sentences _ish_. + +```kotlin +@Test +fun `given a lowercase label, when uppercasing, then returns label uppercased` +``` + +When the input is given directly to the _when_, this can also be represented as... + +```kotlin +@Test +fun `when uppercasing a lowercase label, then returns label uppercased` +``` + +Multiple given or returns statements can be used in the name although it could be a sign that the logic being tested does too much. + +--- + +#### Format + +- Test bodies are broken into sections through the use of blank lines where the sections correspond to the test name. +- Sections can span multiple lines. + +```kotlin +// comments are for illustrative purposes +/* given */ val lowercaseLabel = "hello world" + +/* when */ val result = textUppercaser.uppercase(lowercaseLabel) + +/* then */ result shouldBeEqualTo "HELLO WORLD" +``` + +- Functions extracted from test bodies are placed beneath all the unit tests. + +--- + +#### Assertions + +- Assertions against test results are made using [Kluent's](https://github.com/MarkusAmshove/Kluent) _fluent_ api. +- Typically `shouldBeEqualTo`is the main assertion to use for asserting function return values as by project convention we assert against entire objects or + lists. + +```kotlin +val result = listOf("hello", "world") + +// Fail +result shouldBeEqualTo listOf("hello") +``` + +```kotlin +data class Person(val age: Int, val name: String) + +val result = Person(age = 100, name = "Gandalf") + +// Avoid +result.age shouldBeEqualTo 100 + +// Prefer +result shouldBeEqualTo Person(age = 100, "Gandalf") +``` + +- Exception throwing can be asserted against using `assertFailsWith`. +- When asserting reusable exceptions, include the message to distinguish between them. + +```kotlin +assertFailsWith(message = "Details about error") { + // when section of the test + codeUnderTest() +} +``` + +--- + +#### Constants + +- Reusable values are extracted to file level immutable properties or constants. +- These can be parameters or expected results. +- The naming convention is to prefix with `A` or `AN` for better matching with the test name. + +```kotlin +private const val A_LOWERCASE_LABEL = "hello" + +class MyTest { + @Test + fun `when uppercasing a lowercase label, then returns label uppercased`() { + val result = TextUppercaser().uppercase(A_LOWERCASE_LABEL) + ... + } +} +``` + +--- + +#### Mocking + +- In order to provide different behaviour for dependencies within tests our main method is through mocking, using [Mockk](https://mockk.io/). +- We avoid using relaxed mocks in favour of explicitly declaring mock behaviour through the _Fake_ convention. There are exceptions when mocking framework + classes which would require a lot of boilerplate. +- Using `Spy` is discouraged as it inherently requires real instances, which we are avoiding in our tests. There are exceptions such as `VectorFeatures` which + acts like a `Fixture` in release builds. + +--- + +#### Fakes + +- Fakes are reusable instances of classes purely for testing purposes. They provide functions to replace the functions of the interface/class they're faking + with test specific values. +- When faking an interface, the _Fake_ can be written using delegation or by stubbing +- All Fakes currently reside in the same package `${package}.test.fakes` + +```kotlin +// Delegating to a mock +class FakeClock : Clock by mockk() { + fun givenEpoch(epoch: Long) { + every { epochMillis() } returns epoch + } +} + +// Stubbing the interface +class FakeClock(private val epoch: Long) : Clock { + override fun epochMillis() = epoch +} +``` + +It's currently more common for fakes to fake class behaviour, we achieve this by wrapping and exposing a mock instance. + +```kotlin +class FakeCursor { + val instance = mockk() + fun givenEmpty() { + every { instance.count } returns 0 + every { instance.moveToFirst() } returns false + } +} + +val fakeCursor = FakeCursor().apply { givenEmpty() } +``` + +#### Fixtures + +- Fixtures are a reusable wrappers around data models. They provide default values to make creating instances as easy as possible, with the option to override + specific parameters when needed. +- Are namespaced within an `object`. +- Reduces the _find usages_ noise when searching for usages of the origin class construction. +- All Fixtures currently reside in the same package `${package}.test.fixtures`. + +```kotlin +object ContentAttachmentDataFixture { + fun aContentAttachmentData( + type: ContentAttachmentData.Type.TEXT, + mimeType: String? = null + ) = ContentAttachmentData(type, mimeType) +} +``` + +- Fixtures can also be used to manage specific combinations of parameters + +```kotlin +fun aContentAttachmentAudioData() = aContentAttachmentData( + type = ContentAttachmentData.Type.AUDIO, + mimeType = "audio/mp3", +) +``` + +--- + +### Examples + +##### Extensions used to streamline the test setup + +```kotlin +class CircularCacheTest { + + @Test + fun `when putting more than cache size then cache is limited to cache size`() { + val (cache, internalData) = createIntCache(cacheSize = 3) + + cache.putInOrder(1, 1, 1, 1, 1, 1) + + internalData shouldBeEqualTo arrayOf(1, 1, 1) + } +} + +private fun createIntCache(cacheSize: Int): Pair, Array> { + var internalData: Array? = null + val factory: (Int) -> Array = { + Array(it) { null }.also { array -> internalData = array } + } + return CircularCache(cacheSize, factory) to internalData!! +} + +private fun CircularCache.putInOrder(vararg keys: Int) { + keys.forEach { put(it) } +} +``` + +##### Fakes and Fixtures + +```kotlin +class LateInitUserPropertiesFactoryTest { + + private val fakeActiveSessionDataSource = FakeActiveSessionDataSource() + private val fakeVectorStore = FakeVectorStore() + private val fakeContext = FakeContext() + private val fakeSession = FakeSession().also { + it.givenVectorStore(fakeVectorStore.instance) + } + + private val lateInitUserProperties = LateInitUserPropertiesFactory( + fakeActiveSessionDataSource.instance, + fakeContext.instance + ) + + @Test + fun `given no active session, when creating properties, then returns null`() { + val result = lateInitUserProperties.createUserProperties() + + result shouldBeEqualTo null + } + + @Test + fun `given a teams use case set on an active session, when creating properties, then includes the remapped WorkMessaging selection`() { + fakeVectorStore.givenUseCase(FtueUseCase.TEAMS) + fakeActiveSessionDataSource.setActiveSession(fakeSession) + + val result = lateInitUserProperties.createUserProperties() + + result shouldBeEqualTo UserProperties( + ftueUseCaseSelection = UserProperties.FtueUseCaseSelection.WorkMessaging + ) + } +} + ``` + +##### ViewModel + +- `ViewModels` tend to be one of the most complex areas to unit test due to their position as a coordinator of data flows and bridge between domains. +- As the project uses a slightly tweaked`MvRx`, our API for the `ViewModel` is simplified down to `input - ViewModel.handle(Action)` + and `output Flows - ViewModel.viewEvents & ViewModel.stateFlow`. A `ViewModel` test asserter has been created to further simplify the process. + +```kotlin +class ViewModelTest { + + private var initialState = ViewState.Empty + + @get:Rule + val mvrxTestRule = MvRxTestRule(testDispatcher = UnconfinedTestDispatcher()) + + @Test + fun `when handling MyAction, then emits Loading and Content states`() { + val viewModel = ViewModel(initialState) + val test = viewModel.test() // must be invoked before interacting with the VM + + viewModel.handle(MyAction) + + test + .assertViewStates(initialState, State.Loading, State.Content()) + .assertNoEvents() + .finish() + } +} +``` + +- `ViewModels` often emit multiple states which are copies of the previous state, the `test` extension `assertStatesChanges` allows only the difference to be + supplied. + +```kotlin +data class ViewState(val name: String? = null, val age: Int? = null) +val initialState = ViewState() +val viewModel = ViewModel(initialState) +val test = viewModel.test() + +viewModel.handle(ChangeNameAction("Gandalf")) + +test + .assertStatesChanges( + initialState, + { copy(name = "Gandalf") }, + ) + .finish() +``` From 970abb4dded9c8e8abfdc7b86605466ea52b7af5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 14 Sep 2022 16:53:38 +0200 Subject: [PATCH 005/187] Rename file. --- .../{VectorEventViewModel.kt => VectorSharedActionViewModel.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename vector/src/main/java/im/vector/app/core/platform/{VectorEventViewModel.kt => VectorSharedActionViewModel.kt} (100%) diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorEventViewModel.kt b/vector/src/main/java/im/vector/app/core/platform/VectorSharedActionViewModel.kt similarity index 100% rename from vector/src/main/java/im/vector/app/core/platform/VectorEventViewModel.kt rename to vector/src/main/java/im/vector/app/core/platform/VectorSharedActionViewModel.kt From 64fb985d3bd96fdbd0216a5f0970a8de7df6ff57 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 14 Sep 2022 17:36:59 +0200 Subject: [PATCH 006/187] First draft of documentation to onboard new developers. --- docs/_developer_onboarding.md | 230 ++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 docs/_developer_onboarding.md diff --git a/docs/_developer_onboarding.md b/docs/_developer_onboarding.md new file mode 100644 index 0000000000..2b446a950d --- /dev/null +++ b/docs/_developer_onboarding.md @@ -0,0 +1,230 @@ +# Developer on boarding + + + + + +## Introduction + +This doc is a quick introduction about the project and its architecture. + +It's aim is to help new developers to understand the overall project and where to start developing. + +Other useful documentation: +- all the docs in this folder! +- the [contributing doc](../CONTRIBUTING.md), that you should also read carefully. + +### Quick introduction to Matrix + +Matrix website: [matrix.org](https://matrix.org), [discover page](https://matrix.org/discover). +*Note*: Matrix.org is also hosting a homeserver ([.well-known file](https://matrix.org/.well-known/matrix/client)). +The reference homeserver (this is how Matrix servers are called) implementation is [Synapse](https://github.com/matrix-org/synapse/). But other implementations exist. The Matrix specification is here to ensure that any Matrix client, such as Element Android and its SDK can talk to any Matrix server. + +Have a quick look to the client-server API documentation: [Client-server documentation](https://spec.matrix.org/v1.3/client-server-api/). Other network API exist, the list is here: (https://spec.matrix.org/latest/) + +Matrix is an open source protocol. Change are possible and are tracked using [this GitHub repository](https://github.com/matrix-org/matrix-doc/). Changes to the protocol are called MSC: Matrix Spec Change. These are PullRequest to this project. + +Matrix object are Json data. Unstable prefixes must be used for Json keys when the MSC is not merged (i.e. accepted). + +#### Matrix data + +There are many object and data in the Matrix worlds. Let's focus on the most important and used, `Room` and `Event` + +##### Room + +`Room` is a place which contains ordered `Event`s. They are identified with their `room_id`. Nearly all the data are stored in rooms, and shared using homeserver to all the Room Member. + +*Note*: Spaces are also Rooms with a different `type`. + +##### Event + +`Events` are item of a Room, where data is embedded. + +There are 2 types of Event: + +- Room Events: contain useful content for the user (message, image, etc.), but are not necessarily displayed as this in the timeline (reaction, message edition, call signaling). +- State Events: contain the state of the Room (name, topic, etc.). They have a non null value for the key `state_key`. + +Also all the Room Member details are State Events: one State Event per member. In this casen the `state_key` is the matrixId (= userId). + +Important Fields of an Event: +- `event_id`: unique across the Matrix universe; +- `room_id`: the room the Event belongs to; +- `type`: describe what the Event contain, especially in the `content` section, and how the SDK should handle this Event; +- `content`: dynamic Event data; depends on the `type`. + +So we have a triple `event_id`, `type`, `state_key` which uniquely defines an Event. + +#### Sync + +The `Sync` is a way for the Matrix client to be up to date regarding the user data hosted by the server. All the Events are coming through the sync response. More details can be found here: [spec.matrix.org/v1.3/client-server-api/#syncing](https://spec.matrix.org/v1.3/client-server-api/#syncing) +When the application is in foreground, this is a looping request. We are using Https requests, which offer the advantage to be compatible with any homeserver. A sync token is used as request parameter, to let the server know what the client knows. +The `SyncThread` is responsible to manage the sync request loop. + +When the application is in background, a Push will trigger a sync request. + +##### Glossary about syncs + +- **initial sync**: a sync request without a token. This is the first request a client perform after login or after a clear cache. The server will include in the response all your rooms with the full state (all the room membership Event will not be present), with the latest messages for each room. We are in the process to replace this by version 3: sliding sync. All data are inserted to the Database (currently [Realm](https://www.mongodb.com/docs/realm/sdk/java/)). +- **incremental sync**: sync request with a token. +- **gappy sync**: sync request where all the new Events are not returned for one or several Rooms. Also called `limited sync`. It can be limited per Room. To get all the missing Events, a Room pagination API has to be called. +- **sync token**: `next_batch` value in the previous sync response. Will be provided as the `since` parameter for the next sync request. + +### The Android project + +The project should compile out of the box. + +The project is split into several modules. The main ones are: +For the app +- `vector-app`: application entry point; +- `vector`: legacy application, but now a library. In the process of being splitted into several modules; +- `vector-config`: this is where all the configuration of the application should occurs. Should because we are in the process of migrating all the configuration here; +- `library/ui-strings`: this is where all the string resources are stored. Please refer to [contributing doc](../CONTRIBUTING.md) to know how to make change on this module; +- `library/ui-styles`: this is where the Android styles are defined. + +For the SDK +- `matrix-sdk-android`: the main SDK module. The sources are in this project, but are also exported to [its own project](https://github.com/matrix-org/matrix-android-sdk2). All the PRs and issues related to the SDK take place in the Element Android project; +- `matrix-sdk-android-flow`: contains some wrapper to expose `Flow` to the application. + +### Matrix SDK + +SDK exposes `Services` to the client application. `Services` are public interface, and are defined in this parent package: `org.matrix.android.sdk.api`. Default implementation are internal to the SDK, in this parent package: `org.matrix.android.sdk.internal`. Note that you also have to declare the classes as `internal` when adding classes to the `org.matrix.android.sdk.internal` package. + +Interface allows us to replace the implementation for testing purpose. + +A generated documentation of the SDK is available [here](https://matrix-org.github.io/matrix-android-sdk2/). Updated after each release. Please ensure that the documentation (KDoc) of all the SDK Services is up to date, and is clear for a SDK user. +The SDK generated documentation also contains information about the entry points of the SDK. + +[Dagger](https://dagger.dev/) is used to inject all the dependencies to the SDK classes. + +SDK is exposing data as `LiveData`, but we are progressively migrating to `Flow`. Database is the source of truth. + +Example: +- Client send an Event using the `SendService`; +- At the end a `SendEvent` task is used; +- Retrofit API is used to send data to the server; +- Goes to the server, which returns only the `event_id`; +- The `Event` is coming back from the `sync` response with eventually extra added data. + +### Application + +This is the UI part of the project. + +There are two variants of the application: `Gplay` and `Fdroid`. + +The main difference is about using Firebase on `Gplay` variant, to have Push from Google Services. `FDroid` variant cannot contain closed source dependency. + +`Fdroid` is using background polling to lack the missing of Pushed. Now a solution using UnifiedPush has ben added to the project. See refer to [the dedicated documentation](./unifiedpush.md) for more details. + +#### MvRx + +[Maverick](https://airbnb.io/mavericks/#/README) (or MvRx) is an Android MVI framework that helps to develop Reactive application on Android. + +- Activity: holder for Fragment. See the parent [VectorBaseActivity](../vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt); +- Fragment: manage screen of the application. See the parent [VectorBaseFragment](../vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt); +- BottomSheet: see the parent [VectorBaseBottomSheetDialogFragment](../vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt); +- ViewModel: this is where the logic is placed. All our ViewModel has a `handle()` which takes action as parameter. See the parent [VectorViewModel](../vector/src/main/java/im/vector/app/core/platform/VectorViewModel.kt); +- VectorSharedActionViewModel: Specific ViewModel that can be used to communicate between Fragment(s) and the host Activity. See the parent [VectorSharedActionViewModel](../vector/src/main/java/im/vector/app/core/platform/VectorSharedActionViewModel.kt); +- ViewState: this are `data class`, and this represent the state of the View. Has to be copied and set to be updated. Fragment will update the UI regarding the current state (`invalidate()` method). `Async` class from MvRx can be used in the ViewState, especially for asynchronous data loading. Nullability can also be used for optional data. ViewStates have to implement `MavericksState`; +- ViewEvents: useful when the ViewModel asks the View to trigger a specific action: navigation, show dialog, etc. See the parent [VectorViewEvents](../vector/src/main/java/im/vector/app/core/platform/VectorViewEvents.kt); +- ViewAction (`VectorViewModelAction`): useful when the UI (generally the Fragment) asks the ViewModel to do something. See the parent [VectorViewModelAction](../vector/src/main/java/im/vector/app/core/platform/VectorViewModelAction.kt); +- Controller: see the `Epoxy` section just below. + +##### Behavior + +Fragment asks the ViewModel to perform an action (coming from the user, but not necessarily. ViewModel can then talk to the SDK, updates the state once or several times. Fragment update the UI regarding the new state. + +When ViewModel is instantiated, it can subscribe using the SDK Services to get live state of the data. + +`invalidate()` has to be used by default, but it's possible to listen to specific member(s) of the `ViewState` using `onEach`. TODO Add an example. +`awaitState()` method + +#### Epoxy + +[Epoxy](https://github.com/airbnb/epoxy) is an Android library for building complex screens in a RecyclerView. Please read [the introduction](https://github.com/airbnb/epoxy#epoxy). + +- Controller declares items of the RecyclerView. Controller is injected in the Fragment. Controller extends `EpoxyController`, or one of its subclass, especially `TypedEpoxyController`; +- Fragment gives the state to the controller using `setData`; +- `buildModels` will be called by the framework; +- Controller will create ordered Items. + +Epoxy does the diffing, and handle many other thing for us, like handling item type, etc. + +See for instance the controller [AccountDataEpoxyController](../vector/src/main/java/im/vector/app/features/settings/devtools/AccountDataEpoxyController.kt)) for a simple example. + +Warning: do not use twice the same item `id` or it will crash. + +#### Other frameworks + +- Dependency injection is managed by [Dagger](https://dagger.dev/) (SDK) and [Hilt](https://developer.android.com/training/dependency-injection/hilt-android) (App); +- [Retrofit](https://square.github.io/retrofit/) and [OkHttp3](https://square.github.io/okhttp/): network requests; +- [Moshi](https://github.com/square/moshi) is used to parse and serialize Json object; + +#### Push + +Please see the dedicated documentation for more details. + +This is the classical scenario: + +- App receives a Push. Note: Push is ignored if app is in foreground; +- App asks the SDK to load Event data (fastlane mode). We have a change to get the data faster and display the notification faster; +- App asks the SDK to perform a sync request. + +#### Dependencies management + +All the dependencies are declared in `build.gradle` files. But some versions are declared in [this dedicated file](../dependencies.gradle). + +When adding a new dependency, you will have to update the file [dependencies_groups.gradle](../dependencies_groups.gradle) to allow the dependency to be downloaded from the artifact repository. Sometimes subdependencies need to be added too, until the project can compile. + +[Dependabot](https://github.com/dependabot) is set up on the project. This tool will automatically create Pull Request to upgrade our dependencies one by one. +dependencies_group, gradle files, Dependabot, etc. + +### Other points + +#### Logging + +**Important warning: ** NEVER log private user data, or use the flag `LOG_PRIVATE_DATA`. Be very careful when logging `data class`, all the content will be output! + +[Timber](https://github.com/JakeWharton/timber) is used to log data to logcat. We do not use directly the `Log` class. If possible please use a tag, as per + +````kotlin +Timber.tag(loggerTag.value).d("my log") +```` + +because automatic tag (= class name) will not be available on the release version. + +Also generally it is recommended to provide the `Throwable` to the Timber log functions. + +Last point, not that `Timber.v` function may have no effect on some devices. Prefer using `Timber.d` and up. + +#### Rageshake + +Rageshake is a feature to send bug report directly from the application. Just shake your phone and you will be prompted to send a bug report. + +Bug report can contain: +- a screenshot of the current application state +- the application logs from up to 15 application starts +- the logcat logs +- the key share history (crypto data) + +The data will be sent to an internal server, which is not publicly accessible. A GitHub issue will also be created to a private GitHub repository. + +Rageshake can be very useful to get logs from a release version of the application. + +### Tips + +- Element Android has a `developer mode` in the `Settings/Advanced settings`. Other useful options are available here; +- Show hidden Events can also help to debug feature. When devepor mode is enabled, it is possible to view the source (= the Json content) of any Events; +- Type `/devtools` in Element Web to access a developer menu. On Element Android, available in the Menu of a Room timeline, after enabling developer mode; +- Hidden debug menu: when developer mode is enabled and on debug build, there are some extra screens that can be accessible using the green wheel. In those screens, it will be possible to toggle some feature flags; +- Using logcat, filtering with `onResume` can help you to understand what screen are currently displayed on your device. Searching for string displayed on the screen can also help to find the running code in the codebase. +- When this is possible, prefer using `sealed interface` instead of `sealed class`; +- When writing temporary code, using the string "DO NOT COMMIT" in a comment can help to avoid committing things by mistake. If committed and pushed, the CI will detect this String and will warn the user about it. + +## Happy coding! + +The team is here to support you, feel free to ask anything to other developers. + +Also please feel to update this documentation, if incomplete/wrong/obsolete/etc. + +**Thanks!** From c72ab3d187c5ff5e8583aab9c93e693115124cb1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 14 Sep 2022 17:38:28 +0200 Subject: [PATCH 007/187] Add link to the new doc to the README file. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7acb5aa638..abf9c9a8c5 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,8 @@ Please refer to [CONTRIBUTING.md](https://github.com/vector-im/element-android/b Come chat with the community in the dedicated Matrix [room](https://matrix.to/#/#element-android:matrix.org). +Also [this documentation](./docs/_developer_onboarding.md) can hopefully help developers to start working on the project. + ## Triaging issues Issues are triaged by community members and the Android App Team, following the [triage process](https://github.com/vector-im/element-meta/wiki/Triage-process). From f67cf0d5913e33df94438e14fdb0e4b179643f5f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 14 Sep 2022 17:38:50 +0200 Subject: [PATCH 008/187] Reduce link size. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index abf9c9a8c5..e351b64927 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ If you would like to receive releases more quickly (bearing in mind that they ma ## Contributing -Please refer to [CONTRIBUTING.md](https://github.com/vector-im/element-android/blob/develop/CONTRIBUTING.md) if you want to contribute on Matrix Android projects! +Please refer to [CONTRIBUTING.md](./CONTRIBUTING.md) if you want to contribute on Matrix Android projects! Come chat with the community in the dedicated Matrix [room](https://matrix.to/#/#element-android:matrix.org). From 8623b85ac8ecb19dcd18eb9b334806333a53a6d9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 14 Sep 2022 17:47:31 +0200 Subject: [PATCH 009/187] Add support to `/devtools` command --- docs/_developer_onboarding.md | 2 +- library/ui-strings/src/main/res/values/strings.xml | 1 + .../main/java/im/vector/app/features/command/Command.kt | 1 + .../java/im/vector/app/features/command/CommandParser.kt | 7 +++++++ .../java/im/vector/app/features/command/ParsedCommand.kt | 1 + .../app/features/home/room/detail/TimelineFragment.kt | 3 +++ .../home/room/detail/composer/MessageComposerViewModel.kt | 4 ++++ 7 files changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/_developer_onboarding.md b/docs/_developer_onboarding.md index 2b446a950d..640a2d7665 100644 --- a/docs/_developer_onboarding.md +++ b/docs/_developer_onboarding.md @@ -215,7 +215,7 @@ Rageshake can be very useful to get logs from a release version of the applicati - Element Android has a `developer mode` in the `Settings/Advanced settings`. Other useful options are available here; - Show hidden Events can also help to debug feature. When devepor mode is enabled, it is possible to view the source (= the Json content) of any Events; -- Type `/devtools` in Element Web to access a developer menu. On Element Android, available in the Menu of a Room timeline, after enabling developer mode; +- Type `/devtools` in a Room composer to access a developer menu. There are some other entry points. Developer mode has to be enabled; - Hidden debug menu: when developer mode is enabled and on debug build, there are some extra screens that can be accessible using the green wheel. In those screens, it will be possible to toggle some feature flags; - Using logcat, filtering with `onResume` can help you to understand what screen are currently displayed on your device. Searching for string displayed on the screen can also help to find the running code in the codebase. - When this is possible, prefer using `sealed interface` instead of `sealed class`; diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 6a87ce82f4..23c97661a1 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -1402,6 +1402,7 @@ Changes your avatar in this current room only On/Off markdown To fix Matrix Apps management + Open the developer tools screen Displays information about a user Markdown has been enabled. diff --git a/vector/src/main/java/im/vector/app/features/command/Command.kt b/vector/src/main/java/im/vector/app/features/command/Command.kt index 20c8f9d8fe..433ee32eeb 100644 --- a/vector/src/main/java/im/vector/app/features/command/Command.kt +++ b/vector/src/main/java/im/vector/app/features/command/Command.kt @@ -52,6 +52,7 @@ enum class Command( MARKDOWN("/markdown", null, "", R.string.command_description_markdown, false, false), RAINBOW("/rainbow", null, "", R.string.command_description_rainbow, false, true), RAINBOW_EMOTE("/rainbowme", null, "", R.string.command_description_rainbow_emote, false, true), + DEVTOOLS("/devtools", null, "", R.string.command_description_devtools, true, false), CLEAR_SCALAR_TOKEN("/clear_scalar_token", null, "", R.string.command_description_clear_scalar_token, false, false), SPOILER("/spoiler", null, "", R.string.command_description_spoiler, false, true), SHRUG("/shrug", null, "", R.string.command_description_shrug, false, true), diff --git a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt index be3cabfc18..9cbb6c7978 100644 --- a/vector/src/main/java/im/vector/app/features/command/CommandParser.kt +++ b/vector/src/main/java/im/vector/app/features/command/CommandParser.kt @@ -317,6 +317,13 @@ class CommandParser @Inject constructor() { ParsedCommand.ErrorSyntax(Command.MARKDOWN) } } + Command.DEVTOOLS.matches(slashCommand) -> { + if (messageParts.size == 1) { + ParsedCommand.DevTools + } else { + ParsedCommand.ErrorSyntax(Command.DEVTOOLS) + } + } Command.CLEAR_SCALAR_TOKEN.matches(slashCommand) -> { if (messageParts.size == 1) { ParsedCommand.ClearScalarToken diff --git a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt index 4571deb54f..eba9994218 100644 --- a/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt +++ b/vector/src/main/java/im/vector/app/features/command/ParsedCommand.kt @@ -60,6 +60,7 @@ sealed interface ParsedCommand { data class ChangeAvatarForRoom(val url: String) : ParsedCommand data class SetMarkdown(val enable: Boolean) : ParsedCommand object ClearScalarToken : ParsedCommand + object DevTools : ParsedCommand data class SendSpoiler(val message: String) : ParsedCommand data class SendShrug(val message: CharSequence) : ParsedCommand data class SendLenny(val message: CharSequence) : ParsedCommand diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt index 8b6429abb1..3213bf81fe 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt @@ -1810,6 +1810,9 @@ class TimelineFragment : dismissLoadingDialog() views.composerLayout.setTextIfDifferent("") when (parsedCommand) { + is ParsedCommand.DevTools -> { + navigator.openDevTools(requireContext(), timelineArgs.roomId) + } is ParsedCommand.SetMarkdown -> { showSnackWithMessage(getString(if (parsedCommand.enable) R.string.markdown_has_been_enabled else R.string.markdown_has_been_disabled)) } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt index 7d67ec8c60..30e45bd40b 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt @@ -255,6 +255,10 @@ class MessageComposerViewModel @AssistedInject constructor( is ParsedCommand.SetUserPowerLevel -> { handleSetUserPowerLevel(parsedCommand) } + is ParsedCommand.DevTools -> { + _viewEvents.post(MessageComposerViewEvents.SlashCommandResultOk(parsedCommand)) + popDraft() + } is ParsedCommand.ClearScalarToken -> { // TODO _viewEvents.post(MessageComposerViewEvents.SlashCommandNotImplemented) From b9294381b8884d2065382439d41a6e6fc6aac92d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 14 Sep 2022 17:52:11 +0200 Subject: [PATCH 010/187] Add a paragraph about test. --- docs/_developer_onboarding.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/_developer_onboarding.md b/docs/_developer_onboarding.md index 640a2d7665..bb840826a5 100644 --- a/docs/_developer_onboarding.md +++ b/docs/_developer_onboarding.md @@ -160,7 +160,7 @@ Warning: do not use twice the same item `id` or it will crash. - [Retrofit](https://square.github.io/retrofit/) and [OkHttp3](https://square.github.io/okhttp/): network requests; - [Moshi](https://github.com/square/moshi) is used to parse and serialize Json object; -#### Push +### Push Please see the dedicated documentation for more details. @@ -170,7 +170,7 @@ This is the classical scenario: - App asks the SDK to load Event data (fastlane mode). We have a change to get the data faster and display the notification faster; - App asks the SDK to perform a sync request. -#### Dependencies management +### Dependencies management All the dependencies are declared in `build.gradle` files. But some versions are declared in [this dedicated file](../dependencies.gradle). @@ -179,6 +179,12 @@ When adding a new dependency, you will have to update the file [dependencies_gro [Dependabot](https://github.com/dependabot) is set up on the project. This tool will automatically create Pull Request to upgrade our dependencies one by one. dependencies_group, gradle files, Dependabot, etc. +### Test + +Please refer to [this dedicated document](./ui-tests.md). + +TODO add link to the dedicated screenshot test documentation + ### Other points #### Logging From 7341a65410cba63b593607a79f9fc2be5b951870 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 14 Sep 2022 18:17:15 +0200 Subject: [PATCH 011/187] Run knit. --- docs/_developer_onboarding.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/_developer_onboarding.md b/docs/_developer_onboarding.md index bb840826a5..543cbeba71 100644 --- a/docs/_developer_onboarding.md +++ b/docs/_developer_onboarding.md @@ -2,6 +2,29 @@ +* [Introduction](#introduction) + * [Quick introduction to Matrix](#quick-introduction-to-matrix) + * [Matrix data](#matrix-data) + * [Room](#room) + * [Event](#event) + * [Sync](#sync) + * [Glossary about syncs](#glossary-about-syncs) + * [The Android project](#the-android-project) + * [Matrix SDK](#matrix-sdk) + * [Application](#application) + * [MvRx](#mvrx) + * [Behavior](#behavior) + * [Epoxy](#epoxy) + * [Other frameworks](#other-frameworks) + * [Push](#push) + * [Dependencies management](#dependencies-management) + * [Test](#test) + * [Other points](#other-points) + * [Logging](#logging) + * [Rageshake](#rageshake) + * [Tips](#tips) +* [Happy coding!](#happy-coding) + ## Introduction From bdda8dbc48119ebeb95afe5819b2ffba599f66e9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 14 Sep 2022 18:19:57 +0200 Subject: [PATCH 012/187] Changelogs --- changelog.d/7126.doc | 1 + changelog.d/7126.misc | 1 + 2 files changed, 2 insertions(+) create mode 100644 changelog.d/7126.doc create mode 100644 changelog.d/7126.misc diff --git a/changelog.d/7126.doc b/changelog.d/7126.doc new file mode 100644 index 0000000000..9c69350a11 --- /dev/null +++ b/changelog.d/7126.doc @@ -0,0 +1 @@ +Draft onboarding documentation of the project at `./docs/_developer_onboarding.md` diff --git a/changelog.d/7126.misc b/changelog.d/7126.misc new file mode 100644 index 0000000000..a79d61f819 --- /dev/null +++ b/changelog.d/7126.misc @@ -0,0 +1 @@ +Add support to `/devtools` command. From 5058f942af2a61ddf23080d017d072a3cf1c237d Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 15 Sep 2022 14:18:11 +0100 Subject: [PATCH 013/187] manually including the im.dlg:android-dialer:1.2.5 - avoids using appcompat - avoids using an artifact without a source repository --- library/dialpad/build.gradle | 24 + library/dialpad/src/main/AndroidManifest.xml | 2 + .../android/dialer/animation/AnimUtils.java | 26 + .../dialer/compat/PathInterpolatorCompat.java | 120 +++++ .../dialer/dialpadview/DialpadKeyButton.java | 231 +++++++++ .../dialer/dialpadview/DialpadTextView.java | 73 +++ .../dialer/dialpadview/DialpadView.java | 455 ++++++++++++++++++ .../dialer/dialpadview/DigitsEditText.java | 84 ++++ .../com/android/dialer/util/ViewUtil.java | 41 ++ .../dialer/widget/ResizingTextEditText.java | 55 +++ .../quantum_ic_arrow_back_white_24.png | Bin 0 -> 148 bytes .../quantum_ic_arrow_drop_down_white_18.png | Bin 0 -> 121 bytes .../quantum_ic_backspace_white_24.png | Bin 0 -> 333 bytes .../quantum_ic_block_white_24.png | Bin 0 -> 478 bytes .../quantum_ic_bluetooth_audio_grey600_24.png | Bin 0 -> 448 bytes .../quantum_ic_bluetooth_audio_white_36.png | Bin 0 -> 579 bytes .../quantum_ic_call_end_white_24.png | Bin 0 -> 314 bytes .../quantum_ic_call_end_white_36.png | Bin 0 -> 424 bytes .../quantum_ic_call_made_white_24.png | Bin 0 -> 189 bytes .../quantum_ic_call_merge_white_36.png | Bin 0 -> 258 bytes .../quantum_ic_call_missed_white_24.png | Bin 0 -> 215 bytes .../quantum_ic_call_received_white_24.png | Bin 0 -> 189 bytes .../quantum_ic_call_white_18.png | Bin 0 -> 276 bytes .../quantum_ic_call_white_24.png | Bin 0 -> 340 bytes .../quantum_ic_camera_alt_white_24.png | Bin 0 -> 364 bytes .../quantum_ic_camera_alt_white_48.png | Bin 0 -> 666 bytes .../quantum_ic_check_black_24.png | Bin 0 -> 169 bytes .../quantum_ic_check_circle_googblue_24.png | Bin 0 -> 407 bytes .../quantum_ic_close_white_24.png | Bin 0 -> 221 bytes .../quantum_ic_content_copy_grey600_24.png | Bin 0 -> 203 bytes .../quantum_ic_delete_white_24.png | Bin 0 -> 154 bytes .../quantum_ic_dialpad_white_24.png | Bin 0 -> 264 bytes .../quantum_ic_dialpad_white_36.png | Bin 0 -> 549 bytes .../quantum_ic_edit_grey600_24.png | Bin 0 -> 216 bytes .../quantum_ic_forward_white_24.png | Bin 0 -> 139 bytes .../quantum_ic_fullscreen_exit_white_48.png | Bin 0 -> 105 bytes .../quantum_ic_fullscreen_white_48.png | Bin 0 -> 107 bytes .../quantum_ic_grade_white_24.png | Bin 0 -> 370 bytes .../quantum_ic_group_white_36.png | Bin 0 -> 341 bytes .../quantum_ic_hd_white_24.png | Bin 0 -> 236 bytes .../quantum_ic_headset_grey600_24.png | Bin 0 -> 371 bytes .../quantum_ic_headset_white_36.png | Bin 0 -> 511 bytes .../quantum_ic_history_white_24.png | Bin 0 -> 486 bytes .../quantum_ic_image_white_24.png | Bin 0 -> 261 bytes .../quantum_ic_info_outline_white_24.png | Bin 0 -> 485 bytes .../quantum_ic_message_white_24.png | Bin 0 -> 167 bytes .../quantum_ic_mic_off_black_24.png | Bin 0 -> 402 bytes .../quantum_ic_mic_off_white_36.png | Bin 0 -> 578 bytes .../quantum_ic_more_vert_white_24.png | Bin 0 -> 118 bytes .../quantum_ic_network_wifi_white_24.png | Bin 0 -> 427 bytes .../quantum_ic_pause_white_24.png | Bin 0 -> 105 bytes .../quantum_ic_pause_white_36.png | Bin 0 -> 124 bytes .../quantum_ic_people_white_24.png | Bin 0 -> 236 bytes .../quantum_ic_person_add_white_24.png | Bin 0 -> 289 bytes .../quantum_ic_person_white_24.png | Bin 0 -> 273 bytes .../quantum_ic_photo_library_white_24.png | Bin 0 -> 249 bytes .../quantum_ic_photo_white_24.png | Bin 0 -> 261 bytes .../quantum_ic_photo_white_48.png | Bin 0 -> 450 bytes .../quantum_ic_play_arrow_white_24.png | Bin 0 -> 195 bytes .../quantum_ic_report_white_18.png | Bin 0 -> 212 bytes .../quantum_ic_report_white_24.png | Bin 0 -> 192 bytes .../quantum_ic_report_white_36.png | Bin 0 -> 267 bytes .../quantum_ic_schedule_white_24.png | Bin 0 -> 467 bytes .../quantum_ic_search_white_24.png | Bin 0 -> 396 bytes .../quantum_ic_send_white_24.png | Bin 0 -> 293 bytes .../quantum_ic_signal_wifi_4_bar_white_24.png | Bin 0 -> 339 bytes .../quantum_ic_swap_calls_white_36.png | Bin 0 -> 447 bytes .../quantum_ic_undo_white_48.png | Bin 0 -> 445 bytes .../quantum_ic_videocam_off_white_24.png | Bin 0 -> 271 bytes .../quantum_ic_videocam_off_white_36.png | Bin 0 -> 360 bytes .../quantum_ic_videocam_white_18.png | Bin 0 -> 155 bytes .../quantum_ic_videocam_white_24.png | Bin 0 -> 173 bytes .../quantum_ic_videocam_white_36.png | Bin 0 -> 222 bytes .../quantum_ic_voicemail_white_24.png | Bin 0 -> 478 bytes .../quantum_ic_volume_down_white_24.png | Bin 0 -> 186 bytes .../quantum_ic_volume_up_grey600_24.png | Bin 0 -> 375 bytes .../quantum_ic_volume_up_white_24.png | Bin 0 -> 365 bytes .../quantum_ic_volume_up_white_36.png | Bin 0 -> 518 bytes .../quantum_ic_arrow_back_white_24.png | Bin 0 -> 149 bytes .../quantum_ic_content_copy_grey600_24.png | Bin 0 -> 203 bytes .../quantum_ic_send_white_24.png | Bin 0 -> 295 bytes .../quantum_ic_undo_white_48.png | Bin 0 -> 447 bytes .../quantum_ic_arrow_back_white_24.png | Bin 0 -> 119 bytes .../quantum_ic_content_copy_grey600_24.png | Bin 0 -> 130 bytes .../quantum_ic_send_white_24.png | Bin 0 -> 237 bytes .../quantum_ic_undo_white_48.png | Bin 0 -> 325 bytes .../quantum_ic_arrow_back_white_24.png | Bin 0 -> 140 bytes .../quantum_ic_content_copy_grey600_24.png | Bin 0 -> 194 bytes .../quantum_ic_send_white_24.png | Bin 0 -> 352 bytes .../quantum_ic_undo_white_48.png | Bin 0 -> 571 bytes .../quantum_ic_arrow_back_white_24.png | Bin 0 -> 195 bytes .../quantum_ic_content_copy_grey600_24.png | Bin 0 -> 276 bytes .../quantum_ic_send_white_24.png | Bin 0 -> 452 bytes .../quantum_ic_undo_white_48.png | Bin 0 -> 823 bytes .../quantum_ic_arrow_back_white_24.png | Bin 0 -> 200 bytes .../quantum_ic_content_copy_grey600_24.png | Bin 0 -> 339 bytes .../quantum_ic_send_white_24.png | Bin 0 -> 580 bytes .../quantum_ic_undo_white_48.png | Bin 0 -> 1087 bytes .../quantum_ic_arrow_back_white_24.png | Bin 0 -> 115 bytes .../quantum_ic_arrow_drop_down_white_18.png | Bin 0 -> 89 bytes .../quantum_ic_backspace_white_24.png | Bin 0 -> 234 bytes .../quantum_ic_block_white_24.png | Bin 0 -> 335 bytes .../quantum_ic_bluetooth_audio_grey600_24.png | Bin 0 -> 307 bytes .../quantum_ic_bluetooth_audio_white_36.png | Bin 0 -> 438 bytes .../quantum_ic_call_end_white_24.png | Bin 0 -> 235 bytes .../quantum_ic_call_end_white_36.png | Bin 0 -> 314 bytes .../quantum_ic_call_made_white_24.png | Bin 0 -> 138 bytes .../quantum_ic_call_merge_white_36.png | Bin 0 -> 208 bytes .../quantum_ic_call_missed_white_24.png | Bin 0 -> 156 bytes .../quantum_ic_call_received_white_24.png | Bin 0 -> 138 bytes .../quantum_ic_call_white_18.png | Bin 0 -> 202 bytes .../quantum_ic_call_white_24.png | Bin 0 -> 246 bytes .../quantum_ic_camera_alt_white_24.png | Bin 0 -> 240 bytes .../quantum_ic_camera_alt_white_48.png | Bin 0 -> 446 bytes .../quantum_ic_check_black_24.png | Bin 0 -> 128 bytes .../quantum_ic_check_circle_googblue_24.png | Bin 0 -> 278 bytes .../quantum_ic_close_white_24.png | Bin 0 -> 175 bytes .../quantum_ic_content_copy_grey600_24.png | Bin 0 -> 135 bytes .../quantum_ic_delete_white_24.png | Bin 0 -> 111 bytes .../quantum_ic_dialpad_white_24.png | Bin 0 -> 161 bytes .../quantum_ic_dialpad_white_36.png | Bin 0 -> 264 bytes .../quantum_ic_edit_grey600_24.png | Bin 0 -> 166 bytes .../quantum_ic_forward_white_24.png | Bin 0 -> 117 bytes .../quantum_ic_fullscreen_exit_white_48.png | Bin 0 -> 101 bytes .../quantum_ic_fullscreen_white_48.png | Bin 0 -> 101 bytes .../quantum_ic_grade_white_24.png | Bin 0 -> 271 bytes .../quantum_ic_group_white_36.png | Bin 0 -> 236 bytes .../quantum_ic_hd_white_24.png | Bin 0 -> 154 bytes .../quantum_ic_headset_grey600_24.png | Bin 0 -> 245 bytes .../quantum_ic_headset_white_36.png | Bin 0 -> 350 bytes .../quantum_ic_history_white_24.png | Bin 0 -> 327 bytes .../quantum_ic_image_white_24.png | Bin 0 -> 185 bytes .../quantum_ic_info_outline_white_24.png | Bin 0 -> 320 bytes .../quantum_ic_message_white_24.png | Bin 0 -> 130 bytes .../quantum_ic_mic_off_black_24.png | Bin 0 -> 271 bytes .../quantum_ic_mic_off_white_36.png | Bin 0 -> 428 bytes .../quantum_ic_more_vert_white_24.png | Bin 0 -> 96 bytes .../quantum_ic_network_wifi_white_24.png | Bin 0 -> 299 bytes .../quantum_ic_pause_white_24.png | Bin 0 -> 83 bytes .../quantum_ic_pause_white_36.png | Bin 0 -> 105 bytes .../quantum_ic_people_white_24.png | Bin 0 -> 179 bytes .../quantum_ic_person_add_white_24.png | Bin 0 -> 204 bytes .../quantum_ic_person_white_24.png | Bin 0 -> 188 bytes .../quantum_ic_photo_library_white_24.png | Bin 0 -> 193 bytes .../quantum_ic_photo_white_24.png | Bin 0 -> 185 bytes .../quantum_ic_photo_white_48.png | Bin 0 -> 304 bytes .../quantum_ic_play_arrow_white_24.png | Bin 0 -> 157 bytes .../quantum_ic_report_white_18.png | Bin 0 -> 163 bytes .../quantum_ic_report_white_24.png | Bin 0 -> 148 bytes .../quantum_ic_report_white_36.png | Bin 0 -> 192 bytes .../quantum_ic_schedule_white_24.png | Bin 0 -> 318 bytes .../quantum_ic_search_white_24.png | Bin 0 -> 247 bytes .../quantum_ic_send_white_24.png | Bin 0 -> 237 bytes .../quantum_ic_signal_wifi_4_bar_white_24.png | Bin 0 -> 252 bytes .../quantum_ic_swap_calls_white_36.png | Bin 0 -> 314 bytes .../quantum_ic_undo_white_48.png | Bin 0 -> 321 bytes .../quantum_ic_videocam_off_white_24.png | Bin 0 -> 198 bytes .../quantum_ic_videocam_off_white_36.png | Bin 0 -> 271 bytes .../quantum_ic_videocam_white_18.png | Bin 0 -> 133 bytes .../quantum_ic_videocam_white_24.png | Bin 0 -> 131 bytes .../quantum_ic_videocam_white_36.png | Bin 0 -> 173 bytes .../quantum_ic_voicemail_white_24.png | Bin 0 -> 221 bytes .../quantum_ic_volume_down_white_24.png | Bin 0 -> 139 bytes .../quantum_ic_volume_up_grey600_24.png | Bin 0 -> 256 bytes .../quantum_ic_volume_up_white_24.png | Bin 0 -> 251 bytes .../quantum_ic_volume_up_white_36.png | Bin 0 -> 365 bytes .../main/res/drawable-v21/btn_dialpad_key.xml | 18 + .../quantum_ic_arrow_back_white_24.png | Bin 0 -> 131 bytes .../quantum_ic_arrow_drop_down_white_18.png | Bin 0 -> 123 bytes .../quantum_ic_backspace_white_24.png | Bin 0 -> 392 bytes .../quantum_ic_block_white_24.png | Bin 0 -> 665 bytes .../quantum_ic_bluetooth_audio_grey600_24.png | Bin 0 -> 518 bytes .../quantum_ic_bluetooth_audio_white_36.png | Bin 0 -> 778 bytes .../quantum_ic_call_end_white_24.png | Bin 0 -> 389 bytes .../quantum_ic_call_end_white_36.png | Bin 0 -> 553 bytes .../quantum_ic_call_made_white_24.png | Bin 0 -> 185 bytes .../quantum_ic_call_merge_white_36.png | Bin 0 -> 287 bytes .../quantum_ic_call_missed_white_24.png | Bin 0 -> 210 bytes .../quantum_ic_call_received_white_24.png | Bin 0 -> 193 bytes .../quantum_ic_call_white_18.png | Bin 0 -> 340 bytes .../quantum_ic_call_white_24.png | Bin 0 -> 420 bytes .../quantum_ic_camera_alt_white_24.png | Bin 0 -> 446 bytes .../quantum_ic_camera_alt_white_48.png | Bin 0 -> 894 bytes .../quantum_ic_check_black_24.png | Bin 0 -> 188 bytes .../quantum_ic_check_circle_googblue_24.png | Bin 0 -> 490 bytes .../quantum_ic_close_white_24.png | Bin 0 -> 257 bytes .../quantum_ic_content_copy_grey600_24.png | Bin 0 -> 193 bytes .../quantum_ic_delete_white_24.png | Bin 0 -> 142 bytes .../quantum_ic_dialpad_white_24.png | Bin 0 -> 281 bytes .../quantum_ic_dialpad_white_36.png | Bin 0 -> 362 bytes .../quantum_ic_edit_grey600_24.png | Bin 0 -> 242 bytes .../quantum_ic_forward_white_24.png | Bin 0 -> 159 bytes .../quantum_ic_fullscreen_exit_white_48.png | Bin 0 -> 106 bytes .../quantum_ic_fullscreen_white_48.png | Bin 0 -> 109 bytes .../quantum_ic_grade_white_24.png | Bin 0 -> 479 bytes .../quantum_ic_group_white_36.png | Bin 0 -> 417 bytes .../quantum_ic_hd_white_24.png | Bin 0 -> 201 bytes .../quantum_ic_headset_grey600_24.png | Bin 0 -> 440 bytes .../quantum_ic_headset_white_36.png | Bin 0 -> 610 bytes .../quantum_ic_history_white_24.png | Bin 0 -> 604 bytes .../quantum_ic_image_white_24.png | Bin 0 -> 304 bytes .../quantum_ic_info_outline_white_24.png | Bin 0 -> 655 bytes .../quantum_ic_message_white_24.png | Bin 0 -> 204 bytes .../quantum_ic_mic_off_black_24.png | Bin 0 -> 454 bytes .../quantum_ic_mic_off_white_36.png | Bin 0 -> 713 bytes .../quantum_ic_more_vert_white_24.png | Bin 0 -> 139 bytes .../quantum_ic_network_wifi_white_24.png | Bin 0 -> 538 bytes .../quantum_ic_pause_white_24.png | Bin 0 -> 90 bytes .../quantum_ic_pause_white_36.png | Bin 0 -> 92 bytes .../quantum_ic_people_white_24.png | Bin 0 -> 294 bytes .../quantum_ic_person_add_white_24.png | Bin 0 -> 329 bytes .../quantum_ic_person_white_24.png | Bin 0 -> 312 bytes .../quantum_ic_photo_library_white_24.png | Bin 0 -> 309 bytes .../quantum_ic_photo_white_24.png | Bin 0 -> 304 bytes .../quantum_ic_photo_white_48.png | Bin 0 -> 570 bytes .../quantum_ic_play_arrow_white_24.png | Bin 0 -> 220 bytes .../quantum_ic_report_white_18.png | Bin 0 -> 240 bytes .../quantum_ic_report_white_24.png | Bin 0 -> 208 bytes .../quantum_ic_report_white_36.png | Bin 0 -> 271 bytes .../quantum_ic_schedule_white_24.png | Bin 0 -> 613 bytes .../quantum_ic_search_white_24.png | Bin 0 -> 465 bytes .../quantum_ic_send_white_24.png | Bin 0 -> 344 bytes .../quantum_ic_signal_wifi_4_bar_white_24.png | Bin 0 -> 431 bytes .../quantum_ic_swap_calls_white_36.png | Bin 0 -> 484 bytes .../quantum_ic_undo_white_48.png | Bin 0 -> 563 bytes .../quantum_ic_videocam_off_white_24.png | Bin 0 -> 296 bytes .../quantum_ic_videocam_off_white_36.png | Bin 0 -> 412 bytes .../quantum_ic_videocam_white_18.png | Bin 0 -> 173 bytes .../quantum_ic_videocam_white_24.png | Bin 0 -> 178 bytes .../quantum_ic_videocam_white_36.png | Bin 0 -> 234 bytes .../quantum_ic_voicemail_white_24.png | Bin 0 -> 487 bytes .../quantum_ic_volume_down_white_24.png | Bin 0 -> 212 bytes .../quantum_ic_volume_up_grey600_24.png | Bin 0 -> 459 bytes .../quantum_ic_volume_up_white_24.png | Bin 0 -> 455 bytes .../quantum_ic_volume_up_white_36.png | Bin 0 -> 654 bytes .../quantum_ic_arrow_back_white_24.png | Bin 0 -> 191 bytes .../quantum_ic_arrow_drop_down_white_18.png | Bin 0 -> 126 bytes .../quantum_ic_backspace_white_24.png | Bin 0 -> 543 bytes .../quantum_ic_block_white_24.png | Bin 0 -> 973 bytes .../quantum_ic_bluetooth_audio_grey600_24.png | Bin 0 -> 794 bytes .../quantum_ic_bluetooth_audio_white_36.png | Bin 0 -> 1080 bytes .../quantum_ic_call_end_white_24.png | Bin 0 -> 553 bytes .../quantum_ic_call_end_white_36.png | Bin 0 -> 778 bytes .../quantum_ic_call_made_white_24.png | Bin 0 -> 247 bytes .../quantum_ic_call_merge_white_36.png | Bin 0 -> 388 bytes .../quantum_ic_call_missed_white_24.png | Bin 0 -> 291 bytes .../quantum_ic_call_received_white_24.png | Bin 0 -> 257 bytes .../quantum_ic_call_white_18.png | Bin 0 -> 491 bytes .../quantum_ic_call_white_24.png | Bin 0 -> 597 bytes .../quantum_ic_camera_alt_white_24.png | Bin 0 -> 666 bytes .../quantum_ic_camera_alt_white_48.png | Bin 0 -> 1309 bytes .../quantum_ic_check_black_24.png | Bin 0 -> 254 bytes .../quantum_ic_check_circle_googblue_24.png | Bin 0 -> 717 bytes .../quantum_ic_close_white_24.png | Bin 0 -> 347 bytes .../quantum_ic_content_copy_grey600_24.png | Bin 0 -> 274 bytes .../quantum_ic_delete_white_24.png | Bin 0 -> 177 bytes .../quantum_ic_dialpad_white_24.png | Bin 0 -> 362 bytes .../quantum_ic_dialpad_white_36.png | Bin 0 -> 452 bytes .../quantum_ic_edit_grey600_24.png | Bin 0 -> 305 bytes .../quantum_ic_forward_white_24.png | Bin 0 -> 204 bytes .../quantum_ic_fullscreen_exit_white_48.png | Bin 0 -> 123 bytes .../quantum_ic_fullscreen_white_48.png | Bin 0 -> 123 bytes .../quantum_ic_grade_white_24.png | Bin 0 -> 676 bytes .../quantum_ic_group_white_36.png | Bin 0 -> 581 bytes .../quantum_ic_hd_white_24.png | Bin 0 -> 290 bytes .../quantum_ic_headset_grey600_24.png | Bin 0 -> 635 bytes .../quantum_ic_headset_white_36.png | Bin 0 -> 936 bytes .../quantum_ic_history_white_24.png | Bin 0 -> 870 bytes .../quantum_ic_image_white_24.png | Bin 0 -> 450 bytes .../quantum_ic_info_outline_white_24.png | Bin 0 -> 953 bytes .../quantum_ic_message_white_24.png | Bin 0 -> 269 bytes .../quantum_ic_mic_off_black_24.png | Bin 0 -> 671 bytes .../quantum_ic_mic_off_white_36.png | Bin 0 -> 1044 bytes .../quantum_ic_more_vert_white_24.png | Bin 0 -> 180 bytes .../quantum_ic_network_wifi_white_24.png | Bin 0 -> 786 bytes .../quantum_ic_pause_white_24.png | Bin 0 -> 92 bytes .../quantum_ic_pause_white_36.png | Bin 0 -> 158 bytes .../quantum_ic_people_white_24.png | Bin 0 -> 417 bytes .../quantum_ic_person_add_white_24.png | Bin 0 -> 464 bytes .../quantum_ic_person_white_24.png | Bin 0 -> 440 bytes .../quantum_ic_photo_library_white_24.png | Bin 0 -> 431 bytes .../quantum_ic_photo_white_24.png | Bin 0 -> 450 bytes .../quantum_ic_photo_white_48.png | Bin 0 -> 859 bytes .../quantum_ic_play_arrow_white_24.png | Bin 0 -> 283 bytes .../quantum_ic_report_white_18.png | Bin 0 -> 312 bytes .../quantum_ic_report_white_24.png | Bin 0 -> 271 bytes .../quantum_ic_report_white_36.png | Bin 0 -> 442 bytes .../quantum_ic_schedule_white_24.png | Bin 0 -> 873 bytes .../quantum_ic_search_white_24.png | Bin 0 -> 728 bytes .../quantum_ic_send_white_24.png | Bin 0 -> 446 bytes .../quantum_ic_signal_wifi_4_bar_white_24.png | Bin 0 -> 619 bytes .../quantum_ic_swap_calls_white_36.png | Bin 0 -> 827 bytes .../quantum_ic_undo_white_48.png | Bin 0 -> 815 bytes .../quantum_ic_videocam_off_white_24.png | Bin 0 -> 412 bytes .../quantum_ic_videocam_off_white_36.png | Bin 0 -> 570 bytes .../quantum_ic_videocam_white_18.png | Bin 0 -> 222 bytes .../quantum_ic_videocam_white_24.png | Bin 0 -> 234 bytes .../quantum_ic_videocam_white_36.png | Bin 0 -> 350 bytes .../quantum_ic_voicemail_white_24.png | Bin 0 -> 625 bytes .../quantum_ic_volume_down_white_24.png | Bin 0 -> 291 bytes .../quantum_ic_volume_up_grey600_24.png | Bin 0 -> 673 bytes .../quantum_ic_volume_up_white_24.png | Bin 0 -> 654 bytes .../quantum_ic_volume_up_white_36.png | Bin 0 -> 998 bytes .../quantum_ic_arrow_back_white_24.png | Bin 0 -> 194 bytes .../quantum_ic_arrow_drop_down_white_18.png | Bin 0 -> 152 bytes .../quantum_ic_backspace_white_24.png | Bin 0 -> 724 bytes .../quantum_ic_block_white_24.png | Bin 0 -> 1295 bytes .../quantum_ic_bluetooth_audio_grey600_24.png | Bin 0 -> 952 bytes .../quantum_ic_bluetooth_audio_white_36.png | Bin 0 -> 1391 bytes .../quantum_ic_call_end_white_24.png | Bin 0 -> 712 bytes .../quantum_ic_call_end_white_36.png | Bin 0 -> 1039 bytes .../quantum_ic_call_made_white_24.png | Bin 0 -> 288 bytes .../quantum_ic_call_merge_white_36.png | Bin 0 -> 435 bytes .../quantum_ic_call_missed_white_24.png | Bin 0 -> 355 bytes .../quantum_ic_call_received_white_24.png | Bin 0 -> 287 bytes .../quantum_ic_call_white_18.png | Bin 0 -> 597 bytes .../quantum_ic_call_white_24.png | Bin 0 -> 778 bytes .../quantum_ic_camera_alt_white_24.png | Bin 0 -> 894 bytes .../quantum_ic_camera_alt_white_48.png | Bin 0 -> 1837 bytes .../quantum_ic_check_black_24.png | Bin 0 -> 277 bytes .../quantum_ic_check_circle_googblue_24.png | Bin 0 -> 1017 bytes .../quantum_ic_close_white_24.png | Bin 0 -> 436 bytes .../quantum_ic_content_copy_grey600_24.png | Bin 0 -> 340 bytes .../quantum_ic_delete_white_24.png | Bin 0 -> 229 bytes .../quantum_ic_dialpad_white_24.png | Bin 0 -> 376 bytes .../quantum_ic_dialpad_white_36.png | Bin 0 -> 754 bytes .../quantum_ic_edit_grey600_24.png | Bin 0 -> 360 bytes .../quantum_ic_forward_white_24.png | Bin 0 -> 236 bytes .../quantum_ic_fullscreen_exit_white_48.png | Bin 0 -> 125 bytes .../quantum_ic_fullscreen_white_48.png | Bin 0 -> 124 bytes .../quantum_ic_grade_white_24.png | Bin 0 -> 887 bytes .../quantum_ic_group_white_36.png | Bin 0 -> 809 bytes .../quantum_ic_hd_white_24.png | Bin 0 -> 348 bytes .../quantum_ic_headset_grey600_24.png | Bin 0 -> 856 bytes .../quantum_ic_headset_white_36.png | Bin 0 -> 1246 bytes .../quantum_ic_history_white_24.png | Bin 0 -> 1190 bytes .../quantum_ic_image_white_24.png | Bin 0 -> 570 bytes .../quantum_ic_info_outline_white_24.png | Bin 0 -> 1279 bytes .../quantum_ic_message_white_24.png | Bin 0 -> 342 bytes .../quantum_ic_mic_off_black_24.png | Bin 0 -> 832 bytes .../quantum_ic_mic_off_white_36.png | Bin 0 -> 1326 bytes .../quantum_ic_more_vert_white_24.png | Bin 0 -> 233 bytes .../quantum_ic_network_wifi_white_24.png | Bin 0 -> 1043 bytes .../quantum_ic_pause_white_24.png | Bin 0 -> 94 bytes .../quantum_ic_pause_white_36.png | Bin 0 -> 110 bytes .../quantum_ic_people_white_24.png | Bin 0 -> 539 bytes .../quantum_ic_person_add_white_24.png | Bin 0 -> 610 bytes .../quantum_ic_person_white_24.png | Bin 0 -> 577 bytes .../quantum_ic_photo_library_white_24.png | Bin 0 -> 553 bytes .../quantum_ic_photo_white_24.png | Bin 0 -> 570 bytes .../quantum_ic_photo_white_48.png | Bin 0 -> 1178 bytes .../quantum_ic_play_arrow_white_24.png | Bin 0 -> 343 bytes .../quantum_ic_report_white_18.png | Bin 0 -> 340 bytes .../quantum_ic_report_white_24.png | Bin 0 -> 362 bytes .../quantum_ic_report_white_36.png | Bin 0 -> 531 bytes .../quantum_ic_schedule_white_24.png | Bin 0 -> 1157 bytes .../quantum_ic_search_white_24.png | Bin 0 -> 915 bytes .../quantum_ic_send_white_24.png | Bin 0 -> 576 bytes .../quantum_ic_signal_wifi_4_bar_white_24.png | Bin 0 -> 800 bytes .../quantum_ic_swap_calls_white_36.png | Bin 0 -> 1008 bytes .../quantum_ic_undo_white_48.png | Bin 0 -> 1072 bytes .../quantum_ic_videocam_off_white_24.png | Bin 0 -> 495 bytes .../quantum_ic_videocam_off_white_36.png | Bin 0 -> 716 bytes .../quantum_ic_videocam_white_18.png | Bin 0 -> 234 bytes .../quantum_ic_videocam_white_24.png | Bin 0 -> 290 bytes .../quantum_ic_videocam_white_36.png | Bin 0 -> 437 bytes .../quantum_ic_voicemail_white_24.png | Bin 0 -> 971 bytes .../quantum_ic_volume_down_white_24.png | Bin 0 -> 356 bytes .../quantum_ic_volume_up_grey600_24.png | Bin 0 -> 895 bytes .../quantum_ic_volume_up_white_24.png | Bin 0 -> 878 bytes .../quantum_ic_volume_up_white_36.png | Bin 0 -> 1304 bytes .../src/main/res/drawable/btn_dialpad_key.xml | 28 ++ .../dialpad/src/main/res/layout/dialpad.xml | 96 ++++ .../src/main/res/layout/dialpad_fragment.xml | 31 ++ .../src/main/res/layout/dialpad_key.xml | 35 ++ .../src/main/res/layout/dialpad_key_one.xml | 41 ++ .../src/main/res/layout/dialpad_key_pound.xml | 26 + .../src/main/res/layout/dialpad_key_star.xml | 26 + .../src/main/res/layout/dialpad_key_zero.xml | 37 ++ .../src/main/res/layout/dialpad_view.xml | 24 + .../main/res/layout/dialpad_view_unthemed.xml | 153 ++++++ .../src/main/res/values-af/values-af.xml | 8 + .../src/main/res/values-am/values-am.xml | 8 + .../src/main/res/values-ar/values-ar.xml | 8 + .../src/main/res/values-az/values-az.xml | 8 + .../res/values-b+sr+Latn/values-b+sr+Latn.xml | 8 + .../src/main/res/values-be/values-be.xml | 8 + .../src/main/res/values-bg/values-bg.xml | 8 + .../src/main/res/values-bn/values-bn.xml | 8 + .../src/main/res/values-bs/values-bs.xml | 8 + .../src/main/res/values-ca/values-ca.xml | 8 + .../src/main/res/values-cs/values-cs.xml | 8 + .../src/main/res/values-da/values-da.xml | 8 + .../src/main/res/values-de/values-de.xml | 8 + .../src/main/res/values-el/values-el.xml | 8 + .../main/res/values-en-rAU/values-en-rAU.xml | 8 + .../main/res/values-en-rGB/values-en-rGB.xml | 8 + .../main/res/values-en-rIN/values-en-rIN.xml | 8 + .../main/res/values-es-rUS/values-es-rUS.xml | 8 + .../src/main/res/values-es/values-es.xml | 8 + .../src/main/res/values-et/values-et.xml | 8 + .../src/main/res/values-eu/values-eu.xml | 8 + .../src/main/res/values-fa/values-fa.xml | 8 + .../src/main/res/values-fi/values-fi.xml | 8 + .../main/res/values-fr-rCA/values-fr-rCA.xml | 8 + .../src/main/res/values-fr/values-fr.xml | 8 + .../src/main/res/values-gl/values-gl.xml | 8 + .../src/main/res/values-gu/values-gu.xml | 8 + .../src/main/res/values-hi/values-hi.xml | 8 + .../src/main/res/values-hr/values-hr.xml | 8 + .../src/main/res/values-hu/values-hu.xml | 8 + .../src/main/res/values-hy/values-hy.xml | 8 + .../src/main/res/values-in/values-in.xml | 8 + .../src/main/res/values-is/values-is.xml | 8 + .../src/main/res/values-it/values-it.xml | 8 + .../src/main/res/values-iw/values-iw.xml | 8 + .../src/main/res/values-ja/values-ja.xml | 8 + .../src/main/res/values-ka/values-ka.xml | 8 + .../src/main/res/values-kk/values-kk.xml | 8 + .../src/main/res/values-km/values-km.xml | 8 + .../src/main/res/values-kn/values-kn.xml | 8 + .../src/main/res/values-ko/values-ko.xml | 8 + .../src/main/res/values-ky/values-ky.xml | 8 + .../src/main/res/values-land/values-land.xml | 25 + .../src/main/res/values-lo/values-lo.xml | 8 + .../src/main/res/values-lt/values-lt.xml | 8 + .../src/main/res/values-lv/values-lv.xml | 8 + .../src/main/res/values-mk/values-mk.xml | 8 + .../src/main/res/values-ml/values-ml.xml | 8 + .../src/main/res/values-mn/values-mn.xml | 8 + .../src/main/res/values-mr/values-mr.xml | 8 + .../src/main/res/values-ms/values-ms.xml | 8 + .../src/main/res/values-my/values-my.xml | 8 + .../src/main/res/values-nb/values-nb.xml | 8 + .../src/main/res/values-ne/values-ne.xml | 8 + .../src/main/res/values-nl/values-nl.xml | 8 + .../src/main/res/values-no/values-no.xml | 8 + .../src/main/res/values-pa/values-pa.xml | 8 + .../src/main/res/values-pl/values-pl.xml | 8 + .../main/res/values-pt-rBR/values-pt-rBR.xml | 8 + .../main/res/values-pt-rPT/values-pt-rPT.xml | 8 + .../src/main/res/values-pt/values-pt.xml | 8 + .../src/main/res/values-ro/values-ro.xml | 8 + .../src/main/res/values-ru/values-ru.xml | 8 + .../src/main/res/values-si/values-si.xml | 8 + .../src/main/res/values-sk/values-sk.xml | 8 + .../src/main/res/values-sl/values-sl.xml | 8 + .../src/main/res/values-sq/values-sq.xml | 8 + .../src/main/res/values-sr/values-sr.xml | 8 + .../src/main/res/values-sv/values-sv.xml | 8 + .../src/main/res/values-sw/values-sw.xml | 8 + .../src/main/res/values-ta/values-ta.xml | 8 + .../src/main/res/values-te/values-te.xml | 8 + .../src/main/res/values-th/values-th.xml | 8 + .../src/main/res/values-tl/values-tl.xml | 8 + .../src/main/res/values-tr/values-tr.xml | 8 + .../src/main/res/values-uk/values-uk.xml | 8 + .../src/main/res/values-ur/values-ur.xml | 8 + .../src/main/res/values-uz/values-uz.xml | 8 + .../src/main/res/values-vi/values-vi.xml | 8 + .../main/res/values-zh-rCN/values-zh-rCN.xml | 8 + .../main/res/values-zh-rHK/values-zh-rHK.xml | 8 + .../main/res/values-zh-rTW/values-zh-rTW.xml | 8 + .../src/main/res/values-zu/values-zu.xml | 8 + .../dialpad/src/main/res/values/values.xml | 121 +++++ library/ui-styles/build.gradle | 2 +- settings.gradle | 1 + vector/build.gradle | 2 +- 468 files changed, 2431 insertions(+), 2 deletions(-) create mode 100644 library/dialpad/build.gradle create mode 100644 library/dialpad/src/main/AndroidManifest.xml create mode 100644 library/dialpad/src/main/java/com/android/dialer/animation/AnimUtils.java create mode 100644 library/dialpad/src/main/java/com/android/dialer/compat/PathInterpolatorCompat.java create mode 100644 library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadKeyButton.java create mode 100644 library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java create mode 100644 library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadView.java create mode 100644 library/dialpad/src/main/java/com/android/dialer/dialpadview/DigitsEditText.java create mode 100644 library/dialpad/src/main/java/com/android/dialer/util/ViewUtil.java create mode 100644 library/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_back_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_drop_down_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_backspace_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_block_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_made_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_merge_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_missed_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_received_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_black_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_circle_googblue_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_close_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_content_copy_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_delete_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_edit_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_forward_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_fullscreen_exit_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_fullscreen_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_grade_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_group_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_hd_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_history_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_image_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_info_outline_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_message_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_black_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_more_vert_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_network_wifi_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_people_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_add_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_library_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_play_arrow_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_schedule_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_search_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_send_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_swap_calls_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_undo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_voicemail_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_down_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_arrow_back_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_content_copy_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_send_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_undo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_arrow_back_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_content_copy_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_send_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_undo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_arrow_back_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_content_copy_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_send_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_undo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_arrow_back_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_content_copy_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_send_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_undo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_arrow_back_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_content_copy_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_send_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_undo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_back_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_drop_down_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_backspace_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_block_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_made_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_merge_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_missed_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_received_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_black_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_circle_googblue_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_close_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_content_copy_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_delete_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_edit_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_forward_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_exit_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_grade_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_group_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_hd_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_history_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_image_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_info_outline_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_message_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_black_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_more_vert_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_network_wifi_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_people_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_person_add_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_person_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_library_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_play_arrow_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_schedule_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_search_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_send_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_swap_calls_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_undo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_voicemail_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_down_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-v21/btn_dialpad_key.xml create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_back_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_drop_down_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_backspace_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_block_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_made_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_merge_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_missed_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_received_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_check_black_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_check_circle_googblue_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_close_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_content_copy_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_delete_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_edit_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_forward_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_exit_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_grade_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_group_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_hd_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_history_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_image_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_info_outline_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_message_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_black_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_more_vert_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_network_wifi_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_people_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_add_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_library_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_play_arrow_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_schedule_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_search_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_send_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_swap_calls_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_undo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_voicemail_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_down_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_back_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_backspace_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_block_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_made_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_merge_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_missed_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_received_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_black_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_circle_googblue_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_close_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_content_copy_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_delete_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_dialpad_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_dialpad_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_edit_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_forward_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_grade_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_group_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_hd_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_headset_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_headset_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_history_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_image_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_info_outline_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_message_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_black_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_more_vert_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_network_wifi_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_people_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_add_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_library_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_play_arrow_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_schedule_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_search_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_send_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_swap_calls_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_undo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_off_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_off_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_voicemail_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_down_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_back_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_backspace_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_block_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_end_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_end_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_made_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_merge_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_missed_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_received_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_camera_alt_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_camera_alt_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_black_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_circle_googblue_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_close_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_content_copy_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_delete_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_edit_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_forward_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_grade_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_group_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_hd_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_history_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_image_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_info_outline_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_message_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_black_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_more_vert_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_network_wifi_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_people_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_add_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_library_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_play_arrow_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_schedule_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_search_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_send_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_swap_calls_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_undo_white_48.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_18.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_36.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_voicemail_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_down_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_grey600_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_24.png create mode 100644 library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_36.png create mode 100644 library/dialpad/src/main/res/drawable/btn_dialpad_key.xml create mode 100644 library/dialpad/src/main/res/layout/dialpad.xml create mode 100644 library/dialpad/src/main/res/layout/dialpad_fragment.xml create mode 100644 library/dialpad/src/main/res/layout/dialpad_key.xml create mode 100644 library/dialpad/src/main/res/layout/dialpad_key_one.xml create mode 100644 library/dialpad/src/main/res/layout/dialpad_key_pound.xml create mode 100644 library/dialpad/src/main/res/layout/dialpad_key_star.xml create mode 100644 library/dialpad/src/main/res/layout/dialpad_key_zero.xml create mode 100644 library/dialpad/src/main/res/layout/dialpad_view.xml create mode 100644 library/dialpad/src/main/res/layout/dialpad_view_unthemed.xml create mode 100644 library/dialpad/src/main/res/values-af/values-af.xml create mode 100644 library/dialpad/src/main/res/values-am/values-am.xml create mode 100644 library/dialpad/src/main/res/values-ar/values-ar.xml create mode 100644 library/dialpad/src/main/res/values-az/values-az.xml create mode 100644 library/dialpad/src/main/res/values-b+sr+Latn/values-b+sr+Latn.xml create mode 100644 library/dialpad/src/main/res/values-be/values-be.xml create mode 100644 library/dialpad/src/main/res/values-bg/values-bg.xml create mode 100644 library/dialpad/src/main/res/values-bn/values-bn.xml create mode 100644 library/dialpad/src/main/res/values-bs/values-bs.xml create mode 100644 library/dialpad/src/main/res/values-ca/values-ca.xml create mode 100644 library/dialpad/src/main/res/values-cs/values-cs.xml create mode 100644 library/dialpad/src/main/res/values-da/values-da.xml create mode 100644 library/dialpad/src/main/res/values-de/values-de.xml create mode 100644 library/dialpad/src/main/res/values-el/values-el.xml create mode 100644 library/dialpad/src/main/res/values-en-rAU/values-en-rAU.xml create mode 100644 library/dialpad/src/main/res/values-en-rGB/values-en-rGB.xml create mode 100644 library/dialpad/src/main/res/values-en-rIN/values-en-rIN.xml create mode 100644 library/dialpad/src/main/res/values-es-rUS/values-es-rUS.xml create mode 100644 library/dialpad/src/main/res/values-es/values-es.xml create mode 100644 library/dialpad/src/main/res/values-et/values-et.xml create mode 100644 library/dialpad/src/main/res/values-eu/values-eu.xml create mode 100644 library/dialpad/src/main/res/values-fa/values-fa.xml create mode 100644 library/dialpad/src/main/res/values-fi/values-fi.xml create mode 100644 library/dialpad/src/main/res/values-fr-rCA/values-fr-rCA.xml create mode 100644 library/dialpad/src/main/res/values-fr/values-fr.xml create mode 100644 library/dialpad/src/main/res/values-gl/values-gl.xml create mode 100644 library/dialpad/src/main/res/values-gu/values-gu.xml create mode 100644 library/dialpad/src/main/res/values-hi/values-hi.xml create mode 100644 library/dialpad/src/main/res/values-hr/values-hr.xml create mode 100644 library/dialpad/src/main/res/values-hu/values-hu.xml create mode 100644 library/dialpad/src/main/res/values-hy/values-hy.xml create mode 100644 library/dialpad/src/main/res/values-in/values-in.xml create mode 100644 library/dialpad/src/main/res/values-is/values-is.xml create mode 100644 library/dialpad/src/main/res/values-it/values-it.xml create mode 100644 library/dialpad/src/main/res/values-iw/values-iw.xml create mode 100644 library/dialpad/src/main/res/values-ja/values-ja.xml create mode 100644 library/dialpad/src/main/res/values-ka/values-ka.xml create mode 100644 library/dialpad/src/main/res/values-kk/values-kk.xml create mode 100644 library/dialpad/src/main/res/values-km/values-km.xml create mode 100644 library/dialpad/src/main/res/values-kn/values-kn.xml create mode 100644 library/dialpad/src/main/res/values-ko/values-ko.xml create mode 100644 library/dialpad/src/main/res/values-ky/values-ky.xml create mode 100644 library/dialpad/src/main/res/values-land/values-land.xml create mode 100644 library/dialpad/src/main/res/values-lo/values-lo.xml create mode 100644 library/dialpad/src/main/res/values-lt/values-lt.xml create mode 100644 library/dialpad/src/main/res/values-lv/values-lv.xml create mode 100644 library/dialpad/src/main/res/values-mk/values-mk.xml create mode 100644 library/dialpad/src/main/res/values-ml/values-ml.xml create mode 100644 library/dialpad/src/main/res/values-mn/values-mn.xml create mode 100644 library/dialpad/src/main/res/values-mr/values-mr.xml create mode 100644 library/dialpad/src/main/res/values-ms/values-ms.xml create mode 100644 library/dialpad/src/main/res/values-my/values-my.xml create mode 100644 library/dialpad/src/main/res/values-nb/values-nb.xml create mode 100644 library/dialpad/src/main/res/values-ne/values-ne.xml create mode 100644 library/dialpad/src/main/res/values-nl/values-nl.xml create mode 100644 library/dialpad/src/main/res/values-no/values-no.xml create mode 100644 library/dialpad/src/main/res/values-pa/values-pa.xml create mode 100644 library/dialpad/src/main/res/values-pl/values-pl.xml create mode 100644 library/dialpad/src/main/res/values-pt-rBR/values-pt-rBR.xml create mode 100644 library/dialpad/src/main/res/values-pt-rPT/values-pt-rPT.xml create mode 100644 library/dialpad/src/main/res/values-pt/values-pt.xml create mode 100644 library/dialpad/src/main/res/values-ro/values-ro.xml create mode 100644 library/dialpad/src/main/res/values-ru/values-ru.xml create mode 100644 library/dialpad/src/main/res/values-si/values-si.xml create mode 100644 library/dialpad/src/main/res/values-sk/values-sk.xml create mode 100644 library/dialpad/src/main/res/values-sl/values-sl.xml create mode 100644 library/dialpad/src/main/res/values-sq/values-sq.xml create mode 100644 library/dialpad/src/main/res/values-sr/values-sr.xml create mode 100644 library/dialpad/src/main/res/values-sv/values-sv.xml create mode 100644 library/dialpad/src/main/res/values-sw/values-sw.xml create mode 100644 library/dialpad/src/main/res/values-ta/values-ta.xml create mode 100644 library/dialpad/src/main/res/values-te/values-te.xml create mode 100644 library/dialpad/src/main/res/values-th/values-th.xml create mode 100644 library/dialpad/src/main/res/values-tl/values-tl.xml create mode 100644 library/dialpad/src/main/res/values-tr/values-tr.xml create mode 100644 library/dialpad/src/main/res/values-uk/values-uk.xml create mode 100644 library/dialpad/src/main/res/values-ur/values-ur.xml create mode 100644 library/dialpad/src/main/res/values-uz/values-uz.xml create mode 100644 library/dialpad/src/main/res/values-vi/values-vi.xml create mode 100644 library/dialpad/src/main/res/values-zh-rCN/values-zh-rCN.xml create mode 100644 library/dialpad/src/main/res/values-zh-rHK/values-zh-rHK.xml create mode 100644 library/dialpad/src/main/res/values-zh-rTW/values-zh-rTW.xml create mode 100644 library/dialpad/src/main/res/values-zu/values-zu.xml create mode 100644 library/dialpad/src/main/res/values/values.xml diff --git a/library/dialpad/build.gradle b/library/dialpad/build.gradle new file mode 100644 index 0000000000..6546b59f4a --- /dev/null +++ b/library/dialpad/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + compileSdk versions.compileSdk + + defaultConfig { + minSdk versions.minSdk + targetSdk versions.targetSdk + } + + compileOptions { + sourceCompatibility versions.sourceCompat + targetCompatibility versions.targetCompat + } + + kotlinOptions { + jvmTarget = "11" + } +} + +dependencies { + implementation "com.android.support:appcompat-v7:28.0.0" +} diff --git a/library/dialpad/src/main/AndroidManifest.xml b/library/dialpad/src/main/AndroidManifest.xml new file mode 100644 index 0000000000..1d412d0ae5 --- /dev/null +++ b/library/dialpad/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/library/dialpad/src/main/java/com/android/dialer/animation/AnimUtils.java b/library/dialpad/src/main/java/com/android/dialer/animation/AnimUtils.java new file mode 100644 index 0000000000..b6a32c587c --- /dev/null +++ b/library/dialpad/src/main/java/com/android/dialer/animation/AnimUtils.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.animation; + +import android.view.animation.Interpolator; + +import com.android.dialer.compat.PathInterpolatorCompat; + +public class AnimUtils { + public static final Interpolator EASE_OUT_EASE_IN = + PathInterpolatorCompat.create(0.4f, 0, 0.2f, 1); +} diff --git a/library/dialpad/src/main/java/com/android/dialer/compat/PathInterpolatorCompat.java b/library/dialpad/src/main/java/com/android/dialer/compat/PathInterpolatorCompat.java new file mode 100644 index 0000000000..7139bc4af1 --- /dev/null +++ b/library/dialpad/src/main/java/com/android/dialer/compat/PathInterpolatorCompat.java @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.compat; + +import android.graphics.Path; +import android.graphics.PathMeasure; +import android.os.Build; +import android.view.animation.Interpolator; +import android.view.animation.PathInterpolator; + +public class PathInterpolatorCompat { + + public static Interpolator create( + float controlX1, float controlY1, float controlX2, float controlY2) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + return new PathInterpolator(controlX1, controlY1, controlX2, controlY2); + } + return new PathInterpolatorBase(controlX1, controlY1, controlX2, controlY2); + } + + private static class PathInterpolatorBase implements Interpolator { + + /** Governs the accuracy of the approximation of the {@link Path}. */ + private static final float PRECISION = 0.002f; + + private final float[] mX; + private final float[] mY; + + public PathInterpolatorBase(Path path) { + final PathMeasure pathMeasure = new PathMeasure(path, false /* forceClosed */); + + final float pathLength = pathMeasure.getLength(); + final int numPoints = (int) (pathLength / PRECISION) + 1; + + mX = new float[numPoints]; + mY = new float[numPoints]; + + final float[] position = new float[2]; + for (int i = 0; i < numPoints; ++i) { + final float distance = (i * pathLength) / (numPoints - 1); + pathMeasure.getPosTan(distance, position, null /* tangent */); + + mX[i] = position[0]; + mY[i] = position[1]; + } + } + + public PathInterpolatorBase(float controlX, float controlY) { + this(createQuad(controlX, controlY)); + } + + public PathInterpolatorBase( + float controlX1, float controlY1, float controlX2, float controlY2) { + this(createCubic(controlX1, controlY1, controlX2, controlY2)); + } + + private static Path createQuad(float controlX, float controlY) { + final Path path = new Path(); + path.moveTo(0.0f, 0.0f); + path.quadTo(controlX, controlY, 1.0f, 1.0f); + return path; + } + + private static Path createCubic( + float controlX1, float controlY1, float controlX2, float controlY2) { + final Path path = new Path(); + path.moveTo(0.0f, 0.0f); + path.cubicTo(controlX1, controlY1, controlX2, controlY2, 1.0f, 1.0f); + return path; + } + + @Override + public float getInterpolation(float t) { + if (t <= 0.0f) { + return 0.0f; + } else if (t >= 1.0f) { + return 1.0f; + } + + // Do a binary search for the correct x to interpolate between. + int startIndex = 0; + int endIndex = mX.length - 1; + while (endIndex - startIndex > 1) { + int midIndex = (startIndex + endIndex) / 2; + if (t < mX[midIndex]) { + endIndex = midIndex; + } else { + startIndex = midIndex; + } + } + + final float xRange = mX[endIndex] - mX[startIndex]; + if (xRange == 0) { + return mY[startIndex]; + } + + final float tInRange = t - mX[startIndex]; + final float fraction = tInRange / xRange; + + final float startY = mY[startIndex]; + final float endY = mY[endIndex]; + + return startY + (fraction * (endY - startY)); + } + } +} diff --git a/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadKeyButton.java b/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadKeyButton.java new file mode 100644 index 0000000000..de6d2c6282 --- /dev/null +++ b/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadKeyButton.java @@ -0,0 +1,231 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dialer.dialpadview; + +import android.content.Context; +import android.graphics.RectF; +import android.os.Bundle; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewConfiguration; +import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityManager; +import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.FrameLayout; + +/** + * Custom class for dialpad buttons. + * + *

When touch exploration mode is enabled for accessibility, this class implements the + * lift-to-type interaction model: + * + *

    + *
  • Hovering over the button will cause it to gain accessibility focus + *
  • Removing the hover pointer while inside the bounds of the button will perform a click action + *
  • If long-click is supported, hovering over the button for a longer period of time will switch + * to the long-click action + *
  • Moving the hover pointer outside of the bounds of the button will restore to the normal click + * action + *
+ */ +public class DialpadKeyButton extends FrameLayout { + + /** Timeout before switching to long-click accessibility mode. */ + private static final int LONG_HOVER_TIMEOUT = ViewConfiguration.getLongPressTimeout() * 2; + + /** Accessibility manager instance used to check touch exploration state. */ + private AccessibilityManager mAccessibilityManager; + + /** Bounds used to filter HOVER_EXIT events. */ + private RectF mHoverBounds = new RectF(); + + /** Whether this view is currently in the long-hover state. */ + private boolean mLongHovered; + + /** Alternate content description for long-hover state. */ + private CharSequence mLongHoverContentDesc; + + /** Backup of standard content description. Used for accessibility. */ + private CharSequence mBackupContentDesc; + + /** Backup of clickable property. Used for accessibility. */ + private boolean mWasClickable; + + /** Backup of long-clickable property. Used for accessibility. */ + private boolean mWasLongClickable; + + /** Runnable used to trigger long-click mode for accessibility. */ + private Runnable mLongHoverRunnable; + + private OnPressedListener mOnPressedListener; + + public DialpadKeyButton(Context context, AttributeSet attrs) { + super(context, attrs); + initForAccessibility(context); + } + + public DialpadKeyButton(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + initForAccessibility(context); + } + + public void setOnPressedListener(OnPressedListener onPressedListener) { + mOnPressedListener = onPressedListener; + } + + private void initForAccessibility(Context context) { + mAccessibilityManager = + (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); + } + + public void setLongHoverContentDescription(CharSequence contentDescription) { + mLongHoverContentDesc = contentDescription; + + if (mLongHovered) { + super.setContentDescription(mLongHoverContentDesc); + } + } + + @Override + public void setContentDescription(CharSequence contentDescription) { + if (mLongHovered) { + mBackupContentDesc = contentDescription; + } else { + super.setContentDescription(contentDescription); + } + } + + @Override + public void setPressed(boolean pressed) { + super.setPressed(pressed); + if (mOnPressedListener != null) { + mOnPressedListener.onPressed(this, pressed); + } + } + + @Override + public void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + + mHoverBounds.left = getPaddingLeft(); + mHoverBounds.right = w - getPaddingRight(); + mHoverBounds.top = getPaddingTop(); + mHoverBounds.bottom = h - getPaddingBottom(); + } + + @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + if (action == AccessibilityNodeInfo.ACTION_CLICK) { + simulateClickForAccessibility(); + return true; + } + + return super.performAccessibilityAction(action, arguments); + } + + @Override + public boolean onHoverEvent(MotionEvent event) { + // When touch exploration is turned on, lifting a finger while inside + // the button's hover target bounds should perform a click action. + if (mAccessibilityManager.isEnabled() && mAccessibilityManager.isTouchExplorationEnabled()) { + switch (event.getActionMasked()) { + case MotionEvent.ACTION_HOVER_ENTER: + // Lift-to-type temporarily disables double-tap activation. + mWasClickable = isClickable(); + mWasLongClickable = isLongClickable(); + if (mWasLongClickable && mLongHoverContentDesc != null) { + if (mLongHoverRunnable == null) { + mLongHoverRunnable = + new Runnable() { + @Override + public void run() { + setLongHovered(true); + announceForAccessibility(mLongHoverContentDesc); + } + }; + } + postDelayed(mLongHoverRunnable, LONG_HOVER_TIMEOUT); + } + + setClickable(false); + setLongClickable(false); + break; + case MotionEvent.ACTION_HOVER_EXIT: + if (mHoverBounds.contains(event.getX(), event.getY())) { + if (mLongHovered) { + performLongClick(); + } else { + simulateClickForAccessibility(); + } + } + + cancelLongHover(); + setClickable(mWasClickable); + setLongClickable(mWasLongClickable); + break; + } + } + + return super.onHoverEvent(event); + } + + /** + * When accessibility is on, simulate press and release to preserve the semantic meaning of + * performClick(). Required for Braille support. + */ + private void simulateClickForAccessibility() { + // Checking the press state prevents double activation. + if (isPressed()) { + return; + } + + setPressed(true); + + // Stay consistent with performClick() by sending the event after + // setting the pressed state but before performing the action. + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED); + + setPressed(false); + } + + private void setLongHovered(boolean enabled) { + if (mLongHovered != enabled) { + mLongHovered = enabled; + + // Switch between normal and alternate description, if available. + if (enabled) { + mBackupContentDesc = getContentDescription(); + super.setContentDescription(mLongHoverContentDesc); + } else { + super.setContentDescription(mBackupContentDesc); + } + } + } + + private void cancelLongHover() { + if (mLongHoverRunnable != null) { + removeCallbacks(mLongHoverRunnable); + } + setLongHovered(false); + } + + public interface OnPressedListener { + + void onPressed(View view, boolean pressed); + } +} diff --git a/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java b/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java new file mode 100644 index 0000000000..992d6cbed2 --- /dev/null +++ b/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.dialer.dialpadview; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.widget.TextView; + +import androidx.appcompat.widget.AppCompatTextView; + +/** + * This is a custom text view intended only for rendering the numerals (and star and pound) on the + * dialpad. TextView has built in top/bottom padding to help account for ascenders/descenders. + * + *

Since vertical space is at a premium on the dialpad, particularly if the font size is scaled + * to a larger default, for the dialpad we use this class to more precisely render characters + * according to the precise amount of space they need. + */ +public class DialpadTextView extends AppCompatTextView { + + private Rect mTextBounds = new Rect(); + private String mTextStr; + + public DialpadTextView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + /** Draw the text to fit within the height/width which have been specified during measurement. */ + @Override + public void draw(Canvas canvas) { + Paint paint = getPaint(); + + // Without this, the draw does not respect the style's specified text color. + paint.setColor(getCurrentTextColor()); + + // The text bounds values are relative and can be negative,, so rather than specifying a + // standard origin such as 0, 0, we need to use negative of the left/top bounds. + // For example, the bounds may be: Left: 11, Right: 37, Top: -77, Bottom: 0 + canvas.drawText(mTextStr, -mTextBounds.left, -mTextBounds.top, paint); + } + + /** + * Calculate the pixel-accurate bounds of the text when rendered, and use that to specify the + * height and width. + */ + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + mTextStr = getText().toString(); + getPaint().getTextBounds(mTextStr, 0, mTextStr.length(), mTextBounds); + + int width = resolveSize(mTextBounds.width(), widthMeasureSpec); + int height = resolveSize(mTextBounds.height(), heightMeasureSpec); + setMeasuredDimension(width, height); + } +} diff --git a/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadView.java b/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadView.java new file mode 100644 index 0000000000..5c6ce46257 --- /dev/null +++ b/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadView.java @@ -0,0 +1,455 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dialer.dialpadview; + +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.Spannable; +import android.text.TextUtils; +import android.text.style.TtsSpan; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewPropertyAnimator; +import android.view.accessibility.AccessibilityManager; +import android.widget.EditText; +import android.widget.ImageButton; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.dialer.animation.AnimUtils; + +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Locale; + +/** View that displays a twelve-key phone dialpad. */ +public class DialpadView extends LinearLayout { + + private static final String TAG = DialpadView.class.getSimpleName(); + + private static final double DELAY_MULTIPLIER = 0.66; + private static final double DURATION_MULTIPLIER = 0.8; + // For animation. + private static final int KEY_FRAME_DURATION = 33; + /** {@code True} if the dialpad is in landscape orientation. */ + private final boolean mIsLandscape; + /** {@code True} if the dialpad is showing in a right-to-left locale. */ + private final boolean mIsRtl; + + private final int[] mButtonIds = + new int[] { + R.id.zero, + R.id.one, + R.id.two, + R.id.three, + R.id.four, + R.id.five, + R.id.six, + R.id.seven, + R.id.eight, + R.id.nine, + R.id.star, + R.id.pound + }; + private EditText mDigits; + private ImageButton mDelete; + private View mOverflowMenuButton; + private ViewGroup mRateContainer; + private TextView mIldCountry; + private TextView mIldRate; + private boolean mCanDigitsBeEdited; + private int mTranslateDistance; + + public DialpadView(Context context) { + this(context, null); + } + + public DialpadView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public DialpadView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + mTranslateDistance = + getResources().getDimensionPixelSize(R.dimen.dialpad_key_button_translate_y); + + mIsLandscape = + getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE; + mIsRtl = Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && + TextUtils.getLayoutDirectionFromLocale(Locale.getDefault()) == View.LAYOUT_DIRECTION_RTL; + } + + @Override + protected void onFinishInflate() { + setupKeypad(); + mDigits = (EditText) findViewById(R.id.digits); + mDelete = (ImageButton) findViewById(R.id.deleteButton); + mOverflowMenuButton = findViewById(R.id.dialpad_overflow); + mRateContainer = (ViewGroup) findViewById(R.id.rate_container); + mIldCountry = (TextView) mRateContainer.findViewById(R.id.ild_country); + mIldRate = (TextView) mRateContainer.findViewById(R.id.ild_rate); + + AccessibilityManager accessibilityManager = + (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE); + if (accessibilityManager.isEnabled()) { + // The text view must be selected to send accessibility events. + mDigits.setSelected(true); + } + } + + private void setupKeypad() { + final int[] letterIds = + new int[] { + R.string.dialpad_0_letters, + R.string.dialpad_1_letters, + R.string.dialpad_2_letters, + R.string.dialpad_3_letters, + R.string.dialpad_4_letters, + R.string.dialpad_5_letters, + R.string.dialpad_6_letters, + R.string.dialpad_7_letters, + R.string.dialpad_8_letters, + R.string.dialpad_9_letters, + R.string.dialpad_star_letters, + R.string.dialpad_pound_letters + }; + + final Resources resources = getContext().getResources(); + + DialpadKeyButton dialpadKey; + TextView numberView; + TextView lettersView; + + final Locale currentLocale = resources.getConfiguration().locale; + final NumberFormat nf; + // We translate dialpad numbers only for "fa" and not any other locale + // ("ar" anybody ?). + if ("fa".equals(currentLocale.getLanguage())) { + nf = DecimalFormat.getInstance(resources.getConfiguration().locale); + } else { + nf = DecimalFormat.getInstance(Locale.ENGLISH); + } + + for (int i = 0; i < mButtonIds.length; i++) { + dialpadKey = (DialpadKeyButton) findViewById(mButtonIds[i]); + numberView = (TextView) dialpadKey.findViewById(R.id.dialpad_key_number); + lettersView = (TextView) dialpadKey.findViewById(R.id.dialpad_key_letters); + + final String numberString; + final CharSequence numberContentDescription; + if (mButtonIds[i] == R.id.pound) { + numberString = resources.getString(R.string.dialpad_pound_number); + numberContentDescription = numberString; + } else if (mButtonIds[i] == R.id.star) { + numberString = resources.getString(R.string.dialpad_star_number); + numberContentDescription = numberString; + } else { + numberString = nf.format(i); + // The content description is used for Talkback key presses. The number is + // separated by a "," to introduce a slight delay. Convert letters into a verbatim + // span so that they are read as letters instead of as one word. + String letters = resources.getString(letterIds[i]); + Spannable spannable = + Spannable.Factory.getInstance().newSpannable(numberString + "," + letters); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + spannable.setSpan( + (new TtsSpan.VerbatimBuilder(letters)).build(), + numberString.length() + 1, + numberString.length() + 1 + letters.length(), + Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); + } + numberContentDescription = spannable; + } + + numberView.setText(numberString); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + numberView.setElegantTextHeight(false); + } + dialpadKey.setContentDescription(numberContentDescription); + + if (lettersView != null) { + lettersView.setText(resources.getString(letterIds[i])); + } + } + + final DialpadKeyButton one = (DialpadKeyButton) findViewById(R.id.one); + one.setLongHoverContentDescription(resources.getText(R.string.description_voicemail_button)); + + final DialpadKeyButton zero = (DialpadKeyButton) findViewById(R.id.zero); + zero.setLongHoverContentDescription(resources.getText(R.string.description_image_button_plus)); + } + + private Drawable getDrawableCompat(Context context, int id) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + return context.getDrawable(id); + } else { + return context.getResources().getDrawable(id); + } + } + + public void setShowVoicemailButton(boolean show) { + View view = findViewById(R.id.dialpad_key_voicemail); + if (view != null) { + view.setVisibility(show ? View.VISIBLE : View.INVISIBLE); + } + } + + /** + * Whether or not the digits above the dialer can be edited. + * + * @param canBeEdited If true, the backspace button will be shown and the digits EditText will be + * configured to allow text manipulation. + */ + public void setCanDigitsBeEdited(boolean canBeEdited) { +// View deleteButton = findViewById(R.id.deleteButton); +// deleteButton.setVisibility(canBeEdited ? View.VISIBLE : View.INVISIBLE); +// View overflowMenuButton = findViewById(R.id.dialpad_overflow); +// overflowMenuButton.setVisibility(canBeEdited ? View.VISIBLE : View.GONE); + +// EditText digits = (EditText) findViewById(R.id.digits); +// digits.setClickable(canBeEdited); +// digits.setLongClickable(canBeEdited); +// digits.setFocusableInTouchMode(canBeEdited); +// digits.setCursorVisible(false); + + mCanDigitsBeEdited = canBeEdited; + } + + public void setCallRateInformation(String countryName, String displayRate) { + if (TextUtils.isEmpty(countryName) && TextUtils.isEmpty(displayRate)) { + mRateContainer.setVisibility(View.GONE); + return; + } + mRateContainer.setVisibility(View.VISIBLE); + mIldCountry.setText(countryName); + mIldRate.setText(displayRate); + } + + public boolean canDigitsBeEdited() { + return mCanDigitsBeEdited; + } + + /** + * Always returns true for onHoverEvent callbacks, to fix problems with accessibility due to the + * dialpad overlaying other fragments. + */ + @Override + public boolean onHoverEvent(MotionEvent event) { + return true; + } + + public void animateShow() { + // This is a hack; without this, the setTranslationY is delayed in being applied, and the + // numbers appear at their original position (0) momentarily before animating. + final AnimatorListenerAdapter showListener = new AnimatorListenerAdapter() {}; + + for (int i = 0; i < mButtonIds.length; i++) { + int delay = (int) (getKeyButtonAnimationDelay(mButtonIds[i]) * DELAY_MULTIPLIER); + int duration = (int) (getKeyButtonAnimationDuration(mButtonIds[i]) * DURATION_MULTIPLIER); + final DialpadKeyButton dialpadKey = (DialpadKeyButton) findViewById(mButtonIds[i]); + + ViewPropertyAnimator animator = dialpadKey.animate(); + if (mIsLandscape) { + // Landscape orientation requires translation along the X axis. + // For RTL locales, ensure we translate negative on the X axis. + dialpadKey.setTranslationX((mIsRtl ? -1 : 1) * mTranslateDistance); + animator.translationX(0); + } else { + // Portrait orientation requires translation along the Y axis. + dialpadKey.setTranslationY(mTranslateDistance); + animator.translationY(0); + } + animator + .setInterpolator(AnimUtils.EASE_OUT_EASE_IN) + .setStartDelay(delay) + .setDuration(duration) + .setListener(showListener) + .start(); + } + } + + public EditText getDigits() { + return mDigits; + } + + public ImageButton getDeleteButton() { + return mDelete; + } + + public View getOverflowMenuButton() { + return mOverflowMenuButton; + } + + /** + * Get the animation delay for the buttons, taking into account whether the dialpad is in + * landscape left-to-right, landscape right-to-left, or portrait. + * + * @param buttonId The button ID. + * @return The animation delay. + */ + private int getKeyButtonAnimationDelay(int buttonId) { + if (mIsLandscape) { + if (mIsRtl) { + if (buttonId == R.id.three) { + return KEY_FRAME_DURATION * 1; + } else if (buttonId == R.id.six) { + return KEY_FRAME_DURATION * 2; + } else if (buttonId == R.id.nine) { + return KEY_FRAME_DURATION * 3; + } else if (buttonId == R.id.pound) { + return KEY_FRAME_DURATION * 4; + } else if (buttonId == R.id.two) { + return KEY_FRAME_DURATION * 5; + } else if (buttonId == R.id.five) { + return KEY_FRAME_DURATION * 6; + } else if (buttonId == R.id.eight) { + return KEY_FRAME_DURATION * 7; + } else if (buttonId == R.id.zero) { + return KEY_FRAME_DURATION * 8; + } else if (buttonId == R.id.one) { + return KEY_FRAME_DURATION * 9; + } else if (buttonId == R.id.four) { + return KEY_FRAME_DURATION * 10; + } else if (buttonId == R.id.seven || buttonId == R.id.star) { + return KEY_FRAME_DURATION * 11; + } + } else { + if (buttonId == R.id.one) { + return KEY_FRAME_DURATION * 1; + } else if (buttonId == R.id.four) { + return KEY_FRAME_DURATION * 2; + } else if (buttonId == R.id.seven) { + return KEY_FRAME_DURATION * 3; + } else if (buttonId == R.id.star) { + return KEY_FRAME_DURATION * 4; + } else if (buttonId == R.id.two) { + return KEY_FRAME_DURATION * 5; + } else if (buttonId == R.id.five) { + return KEY_FRAME_DURATION * 6; + } else if (buttonId == R.id.eight) { + return KEY_FRAME_DURATION * 7; + } else if (buttonId == R.id.zero) { + return KEY_FRAME_DURATION * 8; + } else if (buttonId == R.id.three) { + return KEY_FRAME_DURATION * 9; + } else if (buttonId == R.id.six) { + return KEY_FRAME_DURATION * 10; + } else if (buttonId == R.id.nine || buttonId == R.id.pound) { + return KEY_FRAME_DURATION * 11; + } + } + } else { + if (buttonId == R.id.one) { + return KEY_FRAME_DURATION * 1; + } else if (buttonId == R.id.two) { + return KEY_FRAME_DURATION * 2; + } else if (buttonId == R.id.three) { + return KEY_FRAME_DURATION * 3; + } else if (buttonId == R.id.four) { + return KEY_FRAME_DURATION * 4; + } else if (buttonId == R.id.five) { + return KEY_FRAME_DURATION * 5; + } else if (buttonId == R.id.six) { + return KEY_FRAME_DURATION * 6; + } else if (buttonId == R.id.seven) { + return KEY_FRAME_DURATION * 7; + } else if (buttonId == R.id.eight) { + return KEY_FRAME_DURATION * 8; + } else if (buttonId == R.id.nine) { + return KEY_FRAME_DURATION * 9; + } else if (buttonId == R.id.star) { + return KEY_FRAME_DURATION * 10; + } else if (buttonId == R.id.zero || buttonId == R.id.pound) { + return KEY_FRAME_DURATION * 11; + } + } + + Log.wtf(TAG, "Attempted to get animation delay for invalid key button id."); + return 0; + } + + /** + * Get the button animation duration, taking into account whether the dialpad is in landscape + * left-to-right, landscape right-to-left, or portrait. + * + * @param buttonId The button ID. + * @return The animation duration. + */ + private int getKeyButtonAnimationDuration(int buttonId) { + if (mIsLandscape) { + if (mIsRtl) { + if (buttonId == R.id.one + || buttonId == R.id.four + || buttonId == R.id.seven + || buttonId == R.id.star) { + return KEY_FRAME_DURATION * 8; + } else if (buttonId == R.id.two + || buttonId == R.id.five + || buttonId == R.id.eight + || buttonId == R.id.zero) { + return KEY_FRAME_DURATION * 9; + } else if (buttonId == R.id.three + || buttonId == R.id.six + || buttonId == R.id.nine + || buttonId == R.id.pound) { + return KEY_FRAME_DURATION * 10; + } + } else { + if (buttonId == R.id.one + || buttonId == R.id.four + || buttonId == R.id.seven + || buttonId == R.id.star) { + return KEY_FRAME_DURATION * 10; + } else if (buttonId == R.id.two + || buttonId == R.id.five + || buttonId == R.id.eight + || buttonId == R.id.zero) { + return KEY_FRAME_DURATION * 9; + } else if (buttonId == R.id.three + || buttonId == R.id.six + || buttonId == R.id.nine + || buttonId == R.id.pound) { + return KEY_FRAME_DURATION * 8; + } + } + } else { + if (buttonId == R.id.one + || buttonId == R.id.two + || buttonId == R.id.three + || buttonId == R.id.four + || buttonId == R.id.five + || buttonId == R.id.six) { + return KEY_FRAME_DURATION * 10; + } else if (buttonId == R.id.seven || buttonId == R.id.eight || buttonId == R.id.nine) { + return KEY_FRAME_DURATION * 9; + } else if (buttonId == R.id.star || buttonId == R.id.zero || buttonId == R.id.pound) { + return KEY_FRAME_DURATION * 8; + } + } + + Log.wtf(TAG, "Attempted to get animation duration for invalid key button id."); + return 0; + } +} diff --git a/library/dialpad/src/main/java/com/android/dialer/dialpadview/DigitsEditText.java b/library/dialpad/src/main/java/com/android/dialer/dialpadview/DigitsEditText.java new file mode 100644 index 0000000000..053b301eed --- /dev/null +++ b/library/dialpad/src/main/java/com/android/dialer/dialpadview/DigitsEditText.java @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dialer.dialpadview; + +import android.content.Context; +import android.graphics.Rect; +import android.text.InputType; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.inputmethod.InputMethodManager; + +import com.android.dialer.widget.ResizingTextEditText; + +/** EditText which suppresses IME show up. */ +public class DigitsEditText extends ResizingTextEditText { + private OnTextContextMenuClickListener mOnTextContextMenuClickListener; + + public DigitsEditText(Context context, AttributeSet attrs) { + super(context, attrs); + setInputType(getInputType() | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS); + setShowSoftInputOnFocus(false); + } + + @Override + protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) { + super.onFocusChanged(focused, direction, previouslyFocusedRect); + final InputMethodManager imm = + ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE)); + if (imm != null && imm.isActive(this)) { + imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0); + } + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + final boolean ret = super.onTouchEvent(event); + // Must be done after super.onTouchEvent() + final InputMethodManager imm = + ((InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE)); + if (imm != null && imm.isActive(this)) { + imm.hideSoftInputFromWindow(getApplicationWindowToken(), 0); + } + return ret; + } + + @Override + protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { + super.onTextChanged(text, start, lengthBefore, lengthAfter); + if (isCursorVisible()) { + setSelection(getText().length()); + } + } + + @Override + public boolean onTextContextMenuItem(int id) { + boolean value = super.onTextContextMenuItem(id); + if (mOnTextContextMenuClickListener != null) { + mOnTextContextMenuClickListener.onTextContextMenuClickListener(id); + } + return value; + } + + public interface OnTextContextMenuClickListener { + void onTextContextMenuClickListener(int id); + } + + public void setOnTextContextMenuClickListener(OnTextContextMenuClickListener listener) { + this.mOnTextContextMenuClickListener = listener; + } +} diff --git a/library/dialpad/src/main/java/com/android/dialer/util/ViewUtil.java b/library/dialpad/src/main/java/com/android/dialer/util/ViewUtil.java new file mode 100644 index 0000000000..4f6d1dd47c --- /dev/null +++ b/library/dialpad/src/main/java/com/android/dialer/util/ViewUtil.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dialer.util; + +import android.graphics.Paint; +import android.util.TypedValue; +import android.widget.TextView; + +/** Provides static functions to work with views */ +public class ViewUtil { + + private ViewUtil() {} + + public static void resizeText(TextView textView, int originalTextSize, int minTextSize) { + final Paint paint = textView.getPaint(); + final int width = textView.getWidth(); + if (width == 0) { + return; + } + textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, originalTextSize); + float ratio = width / paint.measureText(textView.getText().toString()); + if (ratio <= 1.0f) { + textView.setTextSize( + TypedValue.COMPLEX_UNIT_PX, Math.max(minTextSize, originalTextSize * ratio)); + } + } +} diff --git a/library/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java b/library/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java new file mode 100644 index 0000000000..6ec1261f15 --- /dev/null +++ b/library/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.dialer.widget; + +import android.content.Context; +import android.content.res.TypedArray; +import android.util.AttributeSet; +import android.widget.EditText; + +import androidx.appcompat.widget.AppCompatEditText; + +import com.android.dialer.dialpadview.R; +import com.android.dialer.util.ViewUtil; + +/** EditText which resizes dynamically with respect to text length. */ +public class ResizingTextEditText extends AppCompatEditText { + + private final int mOriginalTextSize; + private final int mMinTextSize; + + public ResizingTextEditText(Context context, AttributeSet attrs) { + super(context, attrs); + mOriginalTextSize = (int) getTextSize(); + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ResizingText); + mMinTextSize = + (int) a.getDimension(R.styleable.ResizingText_resizing_text_min_size, mOriginalTextSize); + a.recycle(); + } + + @Override + protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { + super.onTextChanged(text, start, lengthBefore, lengthAfter); + ViewUtil.resizeText(this, mOriginalTextSize, mMinTextSize); + } + + @Override + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + super.onSizeChanged(w, h, oldw, oldh); + ViewUtil.resizeText(this, mOriginalTextSize, mMinTextSize); + } +} diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_back_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_back_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..cd1972677699802e4ef9723ea50fcb284f9a2d9e GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8w5N+>NCjiE#JmKNKlwlIJIE$G zENCoBR!I0=pY}@Pupe*oHeRjdZG1q?qm{hxZ$A4bPKTOf6Ie1b1fIqz%iQ?l<@&`u s>vn;8mbGbb(!%VA{yVIsrX`2~&0ZQe`%OT@F`zXJp00i_>zopr05HKY)c^nh literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_drop_down_white_18.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_drop_down_white_18.png new file mode 100644 index 0000000000000000000000000000000000000000..41541bb0d01963961a68459622330e9f2b714ac2 GIT binary patch literal 121 zcmeAS@N?(olHy`uVBq!ia0vp^(jd&i0wmS%+S~(D4xTQKAr_~T6C_v{H`qO}zx;pS ze|Cd}`}Jy0Qmy~y|L*5H_g7r$m|IBikxZw{9(&YOdY5E2WyLsbS{7))HGzS_>$ZRD U=C;huK(iP;UHx3vIVCg!0C6lR^#A|> literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_backspace_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_backspace_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..136e8b8c1ad90ec9762816e5e65c6ffdaf2a82e2 GIT binary patch literal 333 zcmV-T0kZyyP)4n0a)-o1yoh)M!OFjFHd~7aP;!l^Xz#x}Y-+uTu@YP75rlv<@26yjwGp4M z|G^8hYyXu;V23lN1$V**X5@EGd2ejx%n@}xrOX;H)b*Z157d@0htLN!a%Xi!@*?w} zpnJ4)0xdCP#sn_EgAUL-0){amCX8VOIu9DLK#NSUC6zEnOZ1>S{2~qZc@0q*f%egq z8Vi#_Ll*dv%~2+SZjqD{<~N}s&;3j@_EutA+Uzk1WZbO4#4qovA^MQcQ%2tv3i!uit#Z?!sMCfBkp29zgD9OYZNH)K& zhhE3KEcE;KKR9#YoC*J7H0|i>DNRk4dM<675#kMEU2yDOEMrHCRH&^~m!a0@Q0^MQ zgA;3(H02hpI`ssgE3boczX6ZF%7kiV+WLSy`Nz;T;KrN~ufi+fN*vM#d>1}!<`)23 zF=#;vZjzW6FjV{v9fL=63CvH00XS5JG`)jwNz50)J{X&+LOb9=mdFH|XRuX;y5J<4 z34$}wsX{%lCY=e^!F?4f!IE?)SO%jiGzCrROwa(67?ewAg4q~Uf<@^}uo4@s2Uevs z!A9(3UxHKVOmGe^s?augk|i^_KG>{6O=HkbWP&|VYE+@%2=o<6%)A$HAgDqLL-3lw z1h?SLd~C6`Ac^?_*cD&3x_}o&%}}?1PTlgq0}SlTA}_UP0JxRapQ9@P&(5q{)-Y?u zhI4%Y9ogpxvSp|)Z+25pcHz)iETseULL7>B#+HtIBNG!N_bzN|r2j;u_aBG;02*@F UkNbLuzyJUM07*qoM6N<$g139mdjJ3c literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..ec2349ca837da9f2a9f15af5ff4406232e2e218c GIT binary patch literal 448 zcmV;x0YCnUP))EU@vMa3vVDI_JXBW-tbb{{*9WL*yuAPn~HkPnKX{wW2yQ&>jO6LO<)fHo?cV(8tG z5^vL{4vJ#v0#{BH0#vy}HKydMA&2X33JW++r@{`UmmkA;IDq3Tqo=ec4+V<86cBueg+=c>jXpXvVcZRRGpUHpe*c9i}}W=6n7 zVTa0BlUGpBN@RuvF%h;Xy+}1jX~AGpl9|P;o?=W=`t)~Di}Dmd$m_KI(Burw5w%I_ zC8{}eVT`4xKpdyk9+j`yFiqp$iK{HtPjS13DEq`nI#c0*EQ?fJQjaNWH%L)-XT#`E zBv4dCQrM>at_73w(N2pYKOkqp7~9AYZn?&Y8bPhQZETmg>1L9nXTRrG`@u}X&*oq7 qa~u`@oNGlt2jrQbBfEd*?_XbLY2fh&vfiKo0000E7`b-XE$mQ`Q>+!Yk1DG`R)Z}ucW@4@gKuDwQ*4F~-a9$LY%&zEoMHi| z@S%Yl<6IpJN8^?zd@9%+aPB=m{1OGE?fUAf*&L049fG}N@+ z!(!-qSddEhWSXXX43bKLJwZr?kxGG)N`XB^NP>|{fQ^vjHbNTAl|w8+{s7pI`h*Uq Rx1Rt2002ovPDHLkV1h@p3akgg)pim>AYHsfBK7ju zq!H)z-0OJToc}XD%TKY`{|dth6{^%&Yp=#4GYn%;_JqF@OQc+r)g?z%83;j!X^wd! zREv~JOdd4F1$MWb(;#7!4HD|@caPl}6FxM^A$IGG(Sy3yOPOu#8We44mL_gPC}*R% zT~X;khE-nS#}K@*f)P9Tg&@Bz(fSkUQPlB!rY{#Nk=21HkmA;40e!M%Zg5K}h;C|+ zeiT@deV0MPrtX+SU)($o9}E)jRKf{m^o@;k%5H~2;`fVCgd!B)8$jl7HbnQskpKVy M07*qoM6N<$f-$p&NB{r; literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_36.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..51456d3d5d39d2cba1f15ce7d0dec9446a021bbc GIT binary patch literal 424 zcmV;Z0ayNsP)cxiU!0JUv|N2 zN?omrMKFP07V1zAPvS#Dg2Va!*K@eGJ97U)xm+%nGhxQ8xAxXlwX-gRVOvQ zwyZ0yW7#WBbEb#I_FMGUhB9q<AR-tzp*Kc))n>1 z3-?`dPQ#JSHJo=<%S)dX_0u(z{jk$krLB2vK~3~o&Adm}q_xczW7D21>X|6Fp8t2H z*g>m|1f%W1cI=`qBg5#pu!U9JhLK`$LnYi{EEqS#ud!k4;mg>tm2g}~ziySr?&;TW zjSx=h>eZ6nrLn4|KGX^E_i_|+ZD&-3@~b#&r57baFYbX!F~D|sSU@G`YJMB{)lo6T zj`@~Q2^JP?aUbjvLvF8+36)^su%}w8!tkqUd7>^7Yz)iTAj??BGM2H7W$X`|t^N+m SO8hGT0000|k0wldT1B8K8i>HfYNCo5DD+hTU10`4=&Oeo> zFY+n4wPQuVlm|CXwalKrG2!F6H~XKiEY07pr)-%n%S1wR++{XtK*z8y*-&D^qb|x fLV@Uo^)2)A+vZOyKVz)}bPt24tDnm{r-UW|%D6=- literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_merge_white_36.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_merge_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..b7aba8072efcd302db5d7ecadc7df25375814f3d GIT binary patch literal 258 zcmeAS@N?(olHy`uVBq!ia0vp^W+2SL0wmRZ7KH(+lb$Y)Ar*{o&u-*BWFXL*$i0bE zG)PRrbE2Vyp3@Y@ZN|(tcOulgpZyUxx$}GXoQK};jwTt(dabnoFq!GDS3`1$F^7`M)b18ewKetun<%cAB6^b~`qtDnm{r-UW| DH~?m8 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_missed_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_missed_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..f188eb9aa54f0460d80220a12bfd0f1b17f07db4 GIT binary patch literal 215 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8LpJWm(LkP61PmmIkc8HltzwBZjc z64##;w>ZrIhH;5YjL(Bq8G$<<|86c3u;bYBr+l-d)~y23)E(T@{>?t#R_JTMKW9fB z|HR7Dq@OIZ5nnG`vE2~h@)DO>yudl2?c{|n-uHPN=QCC)icFPYp4xXyaMs6wWhTiB z=Iv4jk}i?U+OvNB^@wZ>kkdSG(J>{F$K{kEo097>=Q`n87v3*aZ(3t}<@>*u9H2`X NJYD@<);T3K0RSDTP~-pr literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_received_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_received_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..ca2ae411a8f33dc64afd772e02183c2f911b2ee1 GIT binary patch literal 189 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8i>HfYNCo5DGY2`H90iU&DAk@F zb;QYSwSb_uh_^x9(N_5)p)ac6^Z$59`>cB-`JVsJWa$r2HaN{=wBXh-5HFMC>SmwPjjO3$Z(g-B;Z zZeTvjP;-mZD9e`IYLuhu27Oaej;2?ft3^4s2;3l0LOD$N=(0Aydxv3a1NO%A-5V49kkQ!=X zV`%)ixtjF0)a^NIzfT&=3_}@<#bU8k$;l06(wcI^K4~{{!wzW=azjYkD}h|FPQL}Y zV3vL*xgg+~w1(VpOxmv85YnrTksES+&{fCC9j7Gf82Mn8*e6T!#Wk@r`JzB#L%wJb zYcnT5S{uX;NkkS)#&21u+#OWT?<*8xnfup2(UyYu`|TWayHRle3^B=LUseC>Hz3 z2?03L6F2Y)Y1vJelVK0EWmn2Ql$Ly?Q}HYJ&`ey8O(uTi9vWT@jom{_aSLoF;#2pK zl4W-|8up!*EPLl3g1*=uhfkRYaWVLWw$#P9nUaw)p(W=g$}a?K8bsDKc?-L=1LM-h zsPJb*v0}uSlpQ7f(8IPT6#ZR~|J)2!gMLSvx$!&t+WdOxKlA~ZoD~H=l;~Ih0000< KMNUMnLSTYiKb+YB literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_48.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..c8e69dcebb98d43695027fcc7e39a339c84dda51 GIT binary patch literal 666 zcmV;L0%iS)P)y zDuP#FBS9M!QcYr?x(Xj5^OKhEOrZ0;%Xt?M^PS1$oUvkJVg?bG2*VOq|FP&lUkJx< zKARBwK%20%c&{z=j$iacgSVPOZ>ZBRKY6Vs^pYxn!v)X(MaU+{KDTId#}NxSK|*6x zFv$sHenK`COmmFwEtDe)3f@BdM8ToA&@EBW@D_@SSjd>rJ=jul4hPAn$ZYd zQ(^?GM-r@1H!ZY@i{+CPWphGpzG8()mbM9@HXpGBsG>9Ms~`YLf6Qp{EBmWamEC4dDr!XN=Tg=UR*LRnyXqu_l$^Po#V$T zj`&?_>IiL%W{Dt*qP?plloe0b6+u)P>h$wELg`L#hA>QZ`WYP|H+WzkLrdxi*`3}7 zVOSR<9(Dx^Vxd?l7V1BL0REY1s|}3R@&Et;07*qoM6N<$f_%9k Avj6}9 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_black_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_black_24.png new file mode 100644 index 0000000000000000000000000000000000000000..e802d90aeb092474fe4441d4904624e19e33aa19 GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8fv1aONCo5D3wt>m3`ATXUOswm zs!>DU0}Zi!CF}Zao3?c+WX7rAX;65-#MkbG>aQ&;lCuuWh^*oKJm*f^Mtj49JUS|K zC3kA9QTZBNyf;oWReH6**(8&V%UO;ETJJqz@v5Z9C9`KSkL6^E@Mp1sCCtBnrX7fG SR4)PA&EV-=H6vpuY4V)r&ncM-JTtN64LxW}J@+KiK^e55XKEpn2nt{W zT1WxG+@KJ)poMKAm=m-C?MZQIQ05`xd-OT84N9ODjyb>+ypK-w*d}Q0A!hjDNB96u zxhW`uUNB}q#Lxm7(9}UV6|}r!%pjc#QrCyRP zbbjH8+i_3q^JPN_DJUqRf)iCdrnn}&zaRSdK|iV>FO89QOospf002ovPDHLkV1fow BtDyh@ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_close_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_close_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..ceb1a1eebf2b2cc9a008f42010e144f4dab968de GIT binary patch literal 221 zcmV<303!d1P)og+*{ z>6z1@lfD*AYSPav7|k0wldT1B8LpBu^K|kP61+1y&kUbUYLzMOvP{}Bf#wz?+5x;27VN%MiU!ZqH)W;b3b(~K(%*aVhbP+(cI-*GY9U**jo+#QTo zDa+Te-4uv*T<5k{!EhmuU}#zHO8%^=zN#Dycb&Hx{p07m33MHUr>mdKI;Vst0O%t@ A@&Et; literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_delete_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_delete_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..8444f31384d2ae25a63a77d6d516330e0faaf7c4 GIT binary patch literal 154 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8qNj^vNCo5DGv7)vj^h?--U7)npc8c!QkoY=d#Wzp$PzK CgE##E literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..9037f94e843b77bfd389f4405035d5a89ec017cc GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8Lpc~2L|5D)LSlLEP#97J4W-Lrmc z^oE5zvbvn1n<*bv@OviP+}~ZV+Z!+bw6W1UT(BrZZo(pmMim3qOO26>Wu%#`w=guY zMJ7Z&IrpYeS~~khkGSZ}TQj{g)-1dyUz$>tF1K)FTULFE(&79y_xMvY7#PBHPUOrz zd3Swfa+8F+%myx>#)t%Bb>=5_+rK*D!}aNMw;HSGM$Ka_$-!ro9^4RdF39QH z*rs82G{RYAcG4O}#r^dYjFp}&S9pqqo-P0I_0PO_VUxbC;gFvS^csVwtDnm{r-UW| D1Cwe$ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_36.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..82710e72a51d83b567d45e9c8eedb85c5ef7f8f3 GIT binary patch literal 549 zcmV+=0^0qFP)lBJ;|GXhqk&sp6XP$4jS7ld2Gh#L zQlfc)rV?Wqo@$Y`$%0*Mb`j59~|SgdCpta zQkP@ZJw-xWk#l?(GUSY6TdL(LtD#d9vWu^Z?2s2$cUyk4K019N*Kt!7HgH>hvft?Z z5z@lVJz;aV6R%Af0^ts zo0M0QJzPky;MMYwo#GP!@R1Eg5?agvn9(G$TfVX~6OfE4A&kc?=b>lImhl3eu8`x- z3$oy--SU%7(HUdEjkoQVpKKoU)&Fe%nXcicYPbAkH_^EvB+rf_U&z}nTc)oKk|&Cs zWhmqur~O)nOs>K+-muMOT(XZQFVkzV*KTER}~u9YiL`J&%tKO00000NkvXXu0mjfT__B6 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_edit_grey600_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_edit_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..4a27b46968dfb9c1e21be542e4cde53786d2d977 GIT binary patch literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8Lpd`}n05Rc<;uUK<67znUjnB%lT zoOSjO>jrZHe&aAPxf}lZiv5W4?5ggsxKcvI8xw%0}X6k~|OE zOJ=W{x}cX!(>qjZ)xr|v#bGPt7}q}1zS>ALi N44$rjF6*2UngEMnN6Y{K literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_forward_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_forward_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..a0711d377e2c459e5ab603ebe1b57ab2e0385858 GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8kf)1dh{y4_S1)ohDDWJ)&{sG6 zxTr{zSSDMA{G#-$Uoww0P0)ZqizPQS#kM#%xBDt19=+BlEUV#Pe_cgeFA7o*e-4OJ%*1*LDWQwP&pUXO@geCxg CH6INC literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_grade_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_grade_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..86eecdd4a0a40e1fe48095fd5262398828101f17 GIT binary patch literal 370 zcmV-&0ge8NP)MEjoCkkyqJc zlx9X`i)ETwkS+FTW?Qy+z*M1v=~i|a#8f241ZS8cvOyA8iA4hXLVzVoxMpR8b!w_? z(kBBU3RJ0ClMSwb3no;M1&07*qoM6N<$g6P$m>i_@% literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_group_white_36.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_group_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..f98a074ac190fd40fc725a1f408f520c3209ec87 GIT binary patch literal 341 zcmV-b0jmCqP)ku-kj<(NWe^p`gDbEY&dsN)iaL9VMM>YSQyWoT!N zBq>rP8Kb>QHNZ4;(!|9Ss|37I>V<$+rb_Bof(ng}ZZ^0@bHfJR2|)vgN>hqPw#eWr z!xoM5YzKErQ-~ohi0gtOd45J~1pPeV|k0wldT1B8LpW=|K#5Rc=@2@sr%1ARhP*Bdl`pFv22W&dZ*mqcTwf+AjBKal$!G2}|sfMSTMkg2_d0yf%Vz{m6u+dTC zQOa%&Mj3mqDbg;d54Z)b_L$3Z^V9!t8Sms(*scby{_tJ>w1T`(v&6|23gOA?vn4%O kZOZ=tJHa$fyuhC95rK<6`fy85}Sb4q9e04Rc2`2YX_ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_grey600_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..e859c2f31a12e5f03a09408e6fa62042610fe349 GIT binary patch literal 371 zcmV-(0gV2MP)nHOjp@-MnbhKuPrMpYiGi;0s!x;bk4cUT-tp@4H>ieJUAA!8vfSglxX*E8kAwE7oLrR zw)HW5ux6p6?$N_V_N@Iq3zao!MMKxxKeJF(gCrVCv|q7MLxV;fWB30)q?ASN&Jy}J zP<<|_ZlTk;pc4yi(w`Z6W5Ys@V@5MUBaT9UkzG0rqM!k7@;D34-x69p^aWiIimt+b RSFZp7002ovPDHLkV1mG2qw4?w literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_white_36.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..f77f24767c74a59447611fc495261249cb45a4f4 GIT binary patch literal 511 zcmVNbd`3R9Xk?rPBJ8tIgayWFAWJtUgDy6C<}W?7 zK_>w{paA{ckV@C|;a5e~a*C{usZl|V@sj~cFbWzi`;#-aw-wfC8zSLJn;$ z?~p|maWBet$dMjmE_R`?1bGyDFw+w(TkOjRa^0=HYV-Ovw;s98@j$26k^o3&EjUDlnD==OjTY)IrdA0Fz3sZ$BoEpqCdO-;hoq6BLZIZe){urP&{ zU@|!drW=;5u-+;IGcW@)Fcny%c36WmtV}zs)a|~$(F(hAe;kIj!Uo-80d}>)wp0G_ z5@b^gY>hm*m$scPV!wXOWnpn*L}>FF85#Y5eF4EVcF%`%@x1^5002ovPDHLkV1gdX B>4*RT literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_history_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_history_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..485c826fdfc9a03fbfce5306a394a41e5859224f GIT binary patch literal 486 zcmV@P)%g^WrZxE18_6MW`3|&*f|i0!Aw)tk*$Ng$K_@}~6rn-jSQPXU zR7nx42A)Sjzk=Kpp{KfhWiU7zLNvvFRl@)By7hj?&x&3x+rWYlqN#iFf4DSt!d-bqAIR@P^AMt_ z!^wXCykB&=0bC8~rH?qjKwMj7B&Uau(a^{hrOo*JzFv(Bgp|_Jk=K*K+lU-&! z$3W)*&(#mfQqxTUU)pJvc~;xyD*#v32&tsNV!w#)XA9(~`v>{ZLLXH8FMGO~rWmG9 cNTbUB0{C8YQWV1FwEzGB07*qoM6N<$f-E-Tv;Y7A literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_image_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_image_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..b414cf5b6881d6ec172d2a7fbd73ada5bbf167ab GIT binary patch literal 261 zcmV+g0s8)lP)kmW+#V#f>U=9~3v zy5k#|%`o-bRp5gvNWBjKU}@RX_o(#cOX<;tO*2A$>f4JBeW-BBCp2Wv4dAi~>H>ZU-{cI? zse=}k;97{XqEJ|gdQ)z}NLv+h2nN-m6riYd=e>Y~D%A1;c7!A-*ac%VF|-AqWJ2?3 zQF6~|k0wldT1B8K8o~Mgrh{y4_R~@+;40u=$*uLEU zyU8g|s^(yo@Z*(c+>;)Cv%9dxv*GIDxo*#I%b4T|8l5|)^yKmcca4co7cOXDZz(yN z$GkkFHzfSGeag{y|G6gh-dfi%=kLzGJl;vs6QrIsMb)KdOE?^1P)a*Hr_i_S_LpM` Rr-3#zc)I$ztaD0e0s!JVLel^M literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_black_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_black_24.png new file mode 100644 index 0000000000000000000000000000000000000000..1755dbf3fab08d39326fa7a5963a9752a2a70aa2 GIT binary patch literal 402 zcmV;D0d4+?P)VX4gfi6} zj9m3m2%SyJYy1#GIPldM2SSJ%>Wr6uiQayC;Xw_>NjJO~!UyY4fbBYpR=)eYnW}|k wsvhEwPUuW3p+r5gptxnN*0LOz%bEYd9};=|!lODW)&Kwi07*qoM6N<$f_Q1S=>Px# literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_white_36.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..203cb8a9ffca0035313e24692c44d3e2df42b4b2 GIT binary patch literal 578 zcmV-I0=@l-P)tJ6 znuMSxryRm+Q0oVE?<)xT4)Gi>-wrO}=e<0fdoQoyJlt}#|NqQc_p+BfVOGgiWSa7Z z3jpU{(`&{0N@vp!{Ci)TZoyWadPeE!U0vIe$AbC|!w&8NBV8L={%=^{FVM-ouC}ct z7Tq$eaG$E}lRP$#`&exUd2Adv@2G-(-GUX*rno$o=i0G6m&cm8HY|Fs&b4ECE{`>G z?U=~(Mis6R%X4|Gfos6(eMN<9##RjeX);ber^3Az&%MiEt>mzMz`b$u5fyGCo)!W7 zIcyKG8Yi37xaeWPZVr0|@Isv2Z#0&B5wMZN9szu&L_1u~#l5cOut`6IzbwVsUB0-I zn{Wh9+>yhIHvu0gQO}k$b?zSDV_V5$3w{TzDnegd#(A;aadV%bS>x9xh=Onf%uF(3L9!L?z)TC{b5w$GFY_a9T&QG=533WyUSzItf#&2$6$W&o~Pmt>s%g-27wJyZ)Q7| z;M%bS*N!E)c5DoHYVMk`;C}Uxa;;c!ryf*VvA)4&{W0Gw39PjnEZGhAH-lB9vlq-x Q(f|Me07*qoM6N<$f{70hl>h($ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_more_vert_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_more_vert_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..58e092b8af11edf122ced427f863850fb160e9f4 GIT binary patch literal 118 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;t*47)NCo5DOXiFR7+VUKdF#Ijld10T6+Mfw7N+tI;t>%}kJz6)+h@coW*bRyx`E$msKv58EMG!2~=oWMVVyT!Sg=PVQ8&DK2 zwGGh}sWOqz!i-Fqzn4kMoLj!f2lsLBIZu*C3MFKwNRUQjoh+N^6xcvx36*JN5k!PI z844IaRbYiU5pRgXJb7P)z49!eI3ZCM(S;#a>7*IAzla*pjDMp^z$z-1_nFSFbR@Ljcp7Ja*kOdhRy{oMAhQF`^b)=JfL6gdo9U*Uzj`ZZJXp>81u%2 z-}cYZ6v8x_4Kk7voj^>7l87gr1%ggR9kS|+sft^z!mB6d#l_BiP$?R&m@m|R1EA=# zDkjA+SyFa@%3)*awg*!QpKno~{xQ!)2Z_o=*O?k522I^8ZA`Mm2=HT0M&FoW=oeW< Vqh>;b>ihrz002ovPDHLkV1oCcwUPh; literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2ea05c462291e4a4f8bd30856a25ad33fd420f GIT binary patch literal 105 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;fv1aOh{y5d1PRu~43dBH9UPL5 z6iTKi4pRBU?3e%%g Wo9=4Ww>1KdWAJqKb6Mw<&;$U+sVfHn literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_people_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_people_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..25e443424e436c24bcd819eebb352e421a3dd9b1 GIT binary patch literal 236 zcmVTl*FGu z4)ilZQI}7Xr6bF!wCmv0FYNYE*yX6wuPW;cnn->$NjJaj6Iq|;`6YdAaLpSIE-nsl zTn&7C;&-qM@xl*jhNbxCx&6l;f1=)pTOw2a^JvuUoris(2100004lybq4kV;{Vg=74!%q8si1@D1!Y~;t8~ngh-5DKnv{#kwsGok2b=v^KHmC z7J}w^`(N>zp`V8%r(i-$#Sso8&(OU!8p0Y@QXogebTw8F@j`?uG?DWLTvptY#UL0vRj^T=U8sC5Kp^y!Ix=4L?~RA?$$m!Ksc(e}V%44skE nX$-xPl8>R(21pO3?@vRYvpP(_{R(kj00000NkvXXu0mjfT?cqK literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..56708b0bad6c193edb0bb0c7f39897566aff4b20 GIT binary patch literal 273 zcmV+s0q*{ZP)YT@VRsA^f&#CYX5^Hu(?m zF*ENmu~^hkk;cHnKGc!CZfuHXb_5c`ObaRS#^Scz*`3U1&EX^#{sQhg%EAjl*4LW+R-{@p8n z%@rqq6>~g+m`Xejc}@78$CB5ffTf^A)C%S@`FJ7OW7g&Mh`s!-ct-`ry@q900000NkvXXu0mjfH8y21 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..b414cf5b6881d6ec172d2a7fbd73ada5bbf167ab GIT binary patch literal 261 zcmV+g0s8)lP)kmq8m|@f&vEk zXhJXy z)&q8Jdy{=h?m>-(r*@dK*d3epCi{|HgU+qz4*BYtIwp6bB0wo2#+nm8I>3B8iEGdk zTNzJQxB%cRn_*v)JJ1{dbN|paSFGhz>`QV3I>zMAKdKnfM6N&`Di|k|EDy3@h4PVK zk{o2e3gsieq-8-3jN^&)U)Wy&nw9O-LW-|?GEfU&#WGOH2p`=L$UkuoJ#eZRDaa7g sq|daVQ|=KHU?d>_qaXz-NI@l=ck_!~>**H-(*OVf07*qoM6N<$f*#evGXMYp literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_play_arrow_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_play_arrow_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..57c9fa5460323823edb0289c1d15f0f561e0c06e GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8m#2$kh{y4_Q_k`_IEb*R=ADxY zV6uJDq_v_+Z-tYfR|K!cZcn#wZ_1w*Zwfx3^1JLFH&cH)|4gqfmxMH3rgg?BZ~AgX zO7P4Ssfnoy7dsLbs)cmuJnq)8IA+UruCTi)d!Bot@+%Rg#TB=_7E65dSjDj^h($AU t;!LNFTjoCMkvN)I{QpIN|NiIvIZ;mvueQI+xBzq&gQu&X%Q~loCIB@QN?HH_ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_18.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_18.png new file mode 100644 index 0000000000000000000000000000000000000000..f0bb6f5bebfb0cc46cf98c4323c674d23d228bd6 GIT binary patch literal 212 zcmeAS@N?(olHy`uVBq!ia0vp^(jd&i0wmS%+S~(DvproLLn;{WUfIjbWGKM;Q1?L$ zn~;!@so(|vMp@|k0wldT1B8K8yQhm|NCo5DtD%g{h5`&1-MsIt z?Ftn%c1;gXn`LzFuk4=3OFqB9rNL5}zP&$nDot zp7T_2o)Vm(9Oo&|1!Xuv2~JQG-N%?Tw?IJ`|Lj0Dt7_a1PlG~5$z9fy7n?(VKVZd<8nKU;CVf)_l&k347Jl`CzZ_|42S{-3X6 z45Hdx7u@&E4?jG0-+6OX6((u4&leG&?ba|_&3akGk+EiENu|>OGHzOGs#dM0TI!|@ zfRieR(^TmO4LnId{s657iCV$;LPS~9M=2U+YU}*LUw3rH zQ;Qcnzy$r^s~xK1#g4Z>z;ds^fSK|3#|JV%gTsE~pC$2ujIT(D@p=uYO0P(KY4chu zhDBR&Y2z3P(bvirxaYjtsw&1F{{bih#j`lbWN!cf002ov JPDHLkV1h|6*be{z literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_search_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_search_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..bbfbc96cbce0dc0bf2a0b5ac4fa924dab5e34919 GIT binary patch literal 396 zcmV;70dxL|P)MlVO6$ z;_nvIa)$r8oBh5veEc|b;H00d8XJzB8#}e9C&kTuJTUVGfHxC^|AqQ$xx5-GhxGjg zEIhh0QF{S=I4p;1z^yImyK9a$ptVy59RMztM>fsDtPGlg+w5@HC)kgn4PRK;>X_bu z>liu$k6lAU@DxMm;HncEfHsE4VA2Woz#@iDLEQ;$gC>Udz>Bqx=?R#|P|q7U?)b51 zFp8mM0vel{;U#$YTMYT-70m4}o#qm7R{GY4KES6NLjyhAPCNtV)=Qz}P%ED~n5xR4 zWXH^M-kn(oJmjgYZr`;ht%b(a==+MNfO}N{1?^|3m7t{Z0Ju|yP(a=1sbqEPk1B)$ q>JBiDp_nQ^Q9zA@J6g3rP~3lFwlD09o&!k$0000VQ3HrSHE z6pe92Ii6UdJ%&j5VTZvOA|cNOGv1-(spL^YV~B)rww*&UA)(VWhKpQ7(UH)BP*ExL zTnWX6N0wL6B$=bcD_-gxGfz@($gssTLA|ie zkeo=dgGE>t1^U%OH+kxqdLu`dBr;Tps!UqUViT3kv?Ml(DyJ`$h~iK!^m2u%DhYjK zm?um;kk)U^U=vo8N&Q8hu-4QbM}%=8Hzc_vsB_|SM}|j&s4*ySOwq)T#kl;jj-M3; zLlG}~3W@|5xH%=R;7D^%J9nfM4ii{7HOMMFR&iRC8TR?9AXCISqoqQR%rQWXPq*|b l8pg0_FskTSVnH4M-~*;USqwV8p;rI^002ovPDHLkV1nY%i#`AV literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_swap_calls_white_36.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_swap_calls_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..8c3a0edaa381a8e37f51156843e9f53c81767bf3 GIT binary patch literal 447 zcmV;w0YLtVP)unAL`7`$RIIR^tZ zO)i)w3UWc^9>ej%-QiaUV%q!pw)e-6hxaY5R_lP}lsmQ!{Pf9FS9O#;3wjpP*Wyn* z=Ar5OmSt)eyNN6E=DqW~hHl7|%w_6`ZMjRC%3Q{7qxQjFtDg9-_Qml`B`#5O24jyl zV|04bTeY=JB`#st)K-(tYKYCW7`63O`LWW7xsa@{2SJ>DF>T6iZf~#m8tCjHWC)N zKoxUp_mqh(8Uof67Pvqa#T&p6=af1#o~f;5EO3D;uB&}@#i7xy#;Cs8j0G-G#bNK& z*z?Mcp&FN!gas~8qn-9m>VcB6zy+%AyuCop%9zLns_ulxhQ{mH2h3RJZbhnY(M^xM puwmUwxKqIXc@6u2Ygoe?_6r-0n0Le}X3qcs002ovPDHLkV1k(5)|LPO literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_undo_white_48.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_undo_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..4366bb08273e6a0ffba684885ad1249da7a58807 GIT binary patch literal 445 zcmV;u0Yd(XP)+fCW7DciPnTGF2nzPaCLAI|l4#u#IaF~*pG z7=8b=ApWo<_`{MQl_WB$N+-s%nN!^6IUjk)BhImnsdS*C(?N1c6w-nfJSN^{=FyIP zJt#Jbk__i5$-Bo8Dk?!SNt9s>FG$^cR#Qa^3MNs^I9`#ycMPRK2=XRTi*x8M(ntvU zl0*hwdBcw~mP{oGhOwDAAGyF@Rx_DFOk^orIYYd)6beBx?y`^$lnOnGEt$-9q8z65 zj}AIPOEO(7vT4Ci!d;^Dj|)0XGnX`KbAT|1Db$1DE#1jgR+krsH>pJRwL<%47q6eUuXhC|?F247WT2hdnL`wkRJ~L@Vj<{rc64{(! nI`zqR#u#IaF~%5U{wSXS%3x9F6{My+00000NkvXXu0mjfyTHAe literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..aaf5ac2085f43be7db35a99adef0618d0b26b417 GIT binary patch literal 271 zcmV+q0r38bP)qY$Q`@<$b8J9dcetKhA!xO=1{`t^{Z z!G;5B07wQ31tb?$@=+BZwPm0%M~g0rf`|w+++f!t*RCdgs5aJzsFS)`t8H)YPDaVn#!5N+>1(a#4511VMmA>3A>#(y412r_nT#4 zKAQw4(==oLbU0#Gk9x(@)uMnZ95XD`M};F^yYkk6{=FmPO#IWW?gRESTgrWwAIe8y3T5#KK%w zEW~BTbS^ulaRsnl?sSVQf`O%XaD^~8R}6D;1+jfj!LA`QcX8N|n#Acd@iC9eh^^HF z_gi0*z9}8Lkt@NyE5De`+$WcH7C0RrT-94mwau6@zc}BDI1!p;!Bb}d0000&zH2td{DIFnv@>ZC0rqI^E@?5u0 ze3721=$W@C(O>n))Ul0cd&LN-4IbP0l+XkK Dy^uKf literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..d83e0d50c3dd1aa384568f658f815b35819462a0 GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8iKmNWh{y5d1PRu~2?kC7U;UT= zr_N^cXMNj}ZsyAiX8k|Xl(j>y|G(%AHdBGz0OmV0+YdXVc_rZ2gm&|pDnu%I+pP#P>K4HlFJy9Fh}Hqc=h z(_+T-pT7R5)*n~;gIIsX=r7NL+soj&s-|53NZmO8Gg1?0X4a<8oPN)5L5t<8 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_voicemail_white_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_voicemail_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..03a62e15f90fc0cbfc0d743228e74a8ab242c781 GIT binary patch literal 478 zcmV<40U`d0P)9Khkv``(~Y_QNAu3K!9%5J@DOqOlM(kN$}Mg#sr_oWntC3KB%HwNDdL_78XEpZwmIUWW%pfm+M+3^F!iBtTyx*DAAIUHjx%-0 zJ?kx4-~_L`WW8OVm{4WvYftmtUXJmWKRnGV6M{ol&092YlUX>uR zFpP_aA{j0l`Z!>}VUY|64ewJr3A1F)5DJ7&!Yo-cghEOaVT-IS!Wlv{p-fhZ(46vx z&`wqdVV$r+XeX^5wBi4z<(OkvSbv72K|oHQ&^|k0wldT1B8K8qo<2wh{y4_S2l7s7zngJ)KSP& zyb--))(wl94_NpVza=fcn=h!c@!}&njf3IO?Ktk(KL4j8YbD66`!2<1ab k!eMJS{IPxdPh}eO7l)78&qol`;+0PUJZ+yDRo literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_grey600_24.png b/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..49eb8fcc34d9093c8b631e48d4c2750db01aa65e GIT binary patch literal 375 zcmV--0f_#IP)f%(0?HOQ@Ws3f;{aFCR)L-$;KcI z0*mOBUVyqQokU|$4FZaCmTm@%|1Py6$ryBlfHG{Q`@u3dOW8><2Gby*tXS!5uv`HN z#vldu`cgqSI~^?dsFay#V~`B`4-9A?D4VtP8Ccc@TVlfjQPj+Y^LoMjK5`BEQz{MR zd4Tyx$TjGHX&RI#1LnOT-=H3ND1mst27y7T)bZM{Qb{P!ld`~`0_XLE`Mu;N$kU}< z@ci}yEbB~87Fkou2WMx2*Pj zyZkh7Ub{XL@4QGHYZ5VC@2&xYC#cf}!13}qb1co#owXXu+ ztYpS~fIYLb1dH;tFT zz2;wIYCx29Cvl4hF#TPz{h+!vd#T$3+p(akfyB*#i&zkgi5mou@u1B#OYrgsKnsnz z+Kc|g&E`w?Zt8ZxR$M_|>P-9X5lqFj$dR5jE`mEv`I@#*87$`;Bkj(?wbnd?t;=ch zeiL~{?YOJtp!4y=f6Rd@cvWn~cl2a7{|8yIuMqOdjdereUy*tT*z=o!W=nz#U2qqI8%DVHS9B;La#FhH}G1M5tj)!xbAsrGtr(!xXOyw@t1Q zRC<_*2qUDFY1RlTGfaeWWlGXy0QDVAge7G=Fo5!a6>z4EJ-$({bGAX)l@V3OJ>Mu7 z4DM)lWqlrlSL%JDzQEv~YEA1_)*0`X>Je$O_BAb+n-BfS1`Gx?b@@YmB4h)$tEpp3 zZ?yqSIr||Ir4QMFLDZp^DRt5gY*;(m-`C^cf^`J<8Iu$_)E2u1vYp|ou~Pbdnz~~1 zP$yjN>ei!O`Dnz~RBBqUvQC@6VyI8 zE7eWk>(UR`+$1sbf?41XX$j`F;F$g(o+d6>B9eW4%EsS{Hy=>6;S8?@>;M1&07*qo IM6N<$g2G7bqW}N^ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_arrow_back_white_24.png b/library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_arrow_back_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..f5175576277d2a0f5939c65b3c2d0ac1c5e05c81 GIT binary patch literal 149 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8jHioZNCo5DtL97&4h*b;H@DV5 zcer$Ri?geGe#)18+CBJRIgThmTuE5`C;OtuCY#)`@-j? xk+$YpRqJOcx~0`LYnmPF@BjbHx@*&ZNe7m=*}o-KqJZ`=c)I$ztaD0e0su;qG|~V7 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_content_copy_grey600_24.png b/library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_content_copy_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..90bf872ac87135bbdfa5c45856a4655fcae4b211 GIT binary patch literal 203 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8LpBu^K|5Rc=@2@6a$aut}KO+O`M z_QF2!gZE0^Ql4M&Ree%%%#vTGOFiT$6MoC1m8$bqd#$qSvJFx!CTX@S4O{Oj#4mcx zDHnW$cNHtQyaG^0nkDd(gBL@;lu6cw6^_c+6bcSHu{IZk+An4kH0qdg=)b&ObB)LP zz75hxB6iJs!F7pk|9i>Cb*oetotm~VlbfGm(+yuyE<-*Epz9bsUHx3vIVCg!0DZbd Aga7~l literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_send_white_24.png b/library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_send_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..b8d4ce444b9e7fb0d8b634f8dafaef24b47cdc35 GIT binary patch literal 295 zcmV+?0oeYDP)_FsS!bGII%tqPlMr*uF`LXXN;geZCB>X&`KBPE2@zd$#0E2r&`CqS z8`RHEY}y?sY%#|eJv3{YKr0J8qTukq8frU`0}^VwA`8YVqUYQy(!**HNvQFKlu(06 to*2^#?+W=AF{@bIjl|Dwr$%@*{&(uw)JElfA5L+{q4i^`LklClu}A5 zrIb?i{L6CSFUyG~h_bX{BAYnHJznva$6V(a>lsZuDq@Gv5eAW@6|*>xzxynq3F&Y- zU_L7YxJ7sm8B9^X96=BjSk7yrd%_4xxaSxLkzydPF!zj6WZiQNf~dz?0ZLj% zsK#+o5H)dHL&h>je?brlPVlqIO5*Q pnIq)MbL2rvDW#NBN-3p&w|7~JQRkOhaf|=}002ovPDHLkV1iAO%!vR1 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_arrow_back_white_24.png b/library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_arrow_back_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..22a1140ae2a3d368b6e07ebc0b975e47245dad94 GIT binary patch literal 119 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1J5LwKkP60RiG2_1AOB|yn)3SJ z|Ih#JGoucjNBnD4cKbLh*2~7Y5X)LDz literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_content_copy_grey600_24.png b/library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_content_copy_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..01b869a6088bbfdfc6c1ebf3f94678fd4923f033 GIT binary patch literal 130 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1Pfr)e5R22v2@6D~{5#GVKaFkD zGR76HDYG>%2E2;@#kK$TMbkYhPs&PoEn+z)OI|eyG7(U>Ss)en!1Lbv4VfQ~u6&xh e(w0ry?D_(kISvV?z@kva3d;onlIMIAAYrnRjn zNgvoWqkX+9^=U_(DrJ43sWhUgFJdo^Xlq9-=tKhm{5*nHmYJmPof|GH3vfUYTg(yw zkknqdao%Zg0U<=nsV&-^B58$Xrdmn2mHp10qs~QS2+)w z6uWrDXCf(}kugT8Ba3jpbK6l~IN&<|3}8U9P>CcLnznH^MV2U_{}6z zGyGzwJ}($>hGG^ggVX#5!GK#dV{Vvm-tds~9N-XFdBR7MnZVo#X6)yOFoIg%a743# zqx_&7BLo9Z(uC0zzuBibz(Ks26A#!!E=H}~)dYCOh;;B1qYBPyBK!u?fXj@d*DBA0 zbP$2w6!+wL;ed~Yhb@TFCYA-4FLEk%?k&5?BFT>RB>FImk$(0Q50nX Xy7k|^^Yd>400000NkvXXu0mjf_nwbj literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_arrow_back_white_24.png b/library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_arrow_back_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..d858f18e6c2ef050c2d06f205059dc15416f2cde GIT binary patch literal 140 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DU{4pvkP61P*CGWQ3ML3w_tw5$*r?fF2)Ke=00vrbKbycBGWYWuA(2`LjgX=&Mk5bpFS~OdNQHc n{9eUl=^9z-nmXzF`>L{`sut1T`PW_o8qeVA>gTe~DWM4f=v6Kc literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_content_copy_grey600_24.png b/library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_content_copy_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..831b5249cba1625f478b26526c1fda5bc6acc3ad GIT binary patch literal 194 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DPEQxdkch)?Z+LSZP~c&?Fwbqz zgE^)&3k<%{Y2udKR`z@c)I$ztaD0e0szF?M!*07 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_send_white_24.png b/library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_send_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..4735a7d71186c6c3762b44d2e6686dc793d9e7cf GIT binary patch literal 352 zcmV-m0iXVfP)c)f~kIRddy&k<*_Najm@&Oh&u4^P)hv>m5YOPBxUgP1p+9@65bJsH_RemF!QYk5Y1LR*x+F+ zg#ygC8$dFq;l?Hx3&<2;zO4XiaUTh<>1>{FF@UUWL((B~n&(>ypenDB_KI4j`4$4` zf(wx6VTfUVWC6rsGQs)4F-FjsB4i^K2}npFVl(ZSVUqj*bi8TnVX(cKZ_Ov zsOWQked+lY0!YMl%zDYsw-GQLv)S_VEd-E{kC^Nwp1^#8fEAcLB!&EZ3jt)~GbRlM z=8FVO#blqre2D-O^33>^pGRQ6NI*kO#tO_A3fRi8Tx1oPFBFi3`mEy(-`gTSU*Jt# zhc&zc0LsbFm-(DdNG(!-d8E37P5WdOf~=j002ov JPDHLkV1lTp`y2oO literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_arrow_back_white_24.png b/library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_arrow_back_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..614ad49a3e4fb4c29193b38001841b2486038bcc GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawx;$MRLn;{G-aIJS=qSJz$k|}b zAv!@tz-zVTU&e;~?YopKHgDc88Jd=scC0T}DBXXm(<2Wc_L=IGbWV7a$LuiANph1^ zYL%|ZD|=2V;Rg~&*ne|y9`g9$K50Sht>ypX*X;OyaH8^awdJDcg8JsfS%h1zEl>-b p(-kX{uE0A-=F+*(Aqha^^;^!r*r#k!Pz7`qgQu&X%Q~loCIBM{NiF~Y literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_content_copy_grey600_24.png b/library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_content_copy_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..71f3bd68389c741012825cf9647dc19daa17b5c0 GIT binary patch literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawZhN{ohEy=Vy=k9y*g?SUd)_+DzxvADPA9cm{g1cTWX&%L zRIt})H4rMA69R3SkG1#yv*?;?H!%KGTuXZGb?*90WJykE_Yu=W) zfc{pKDo1aDjL%JSjtlN`Z(6+Lz3v1DCQhJ6Wa7)N1@l2-eJnyA3-(*UqFAiVM(zgU&jBzckP4x+!9sw6g-ZFEmR2=pd{ Mr>mdKI;Vst046tVTL1t6 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_send_white_24.png b/library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_send_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..4a9e2c24aad3a987694cd596dca35c06e8dccb98 GIT binary patch literal 452 zcmV;#0XzPQP)B?^07Cmn=e#9p8EJ|;K$0|$WG+Mz{haYNDVs?4 zLNu~Yl4#QUDuptVsSssMa*GRT`$&?EPNY6gkyr`INX9}mvPP14WQ`*!2vNp_j1-S} zG7U14p^%JZEJUe{WGX}ht0YmxB~mXZ3I-`I*hI_Jo-^2w!svho`%y0fDqtTFiOScCfsp*-H5QUk#<%uk&=i-vCG;000000000000000vwq>$(}r8mBS?>+M~|RK&(EDbD9o*f z0T|4&ZQHhO+qP}nwr$(CZQEws)zoe`S-$E2T*4%ua|UEG%i6{LCtdF-n_0+s?cpJb&)8OVr2G7&mVWnuLo8vWmhr>`nbRSjQ_@HUFFM+6t>Fm+ zGP^T;tC_v;C^I+C6Aol7yLeTrddqf3YMdts$P~`;zgG9F<4w{SPXLgaU8Sg960j3q0%Qv%_4SuqZEp_4BpEWih3)5V z|EseQAbYB)yv4eMW4rEWYRdlskk|t(p z_vRMJW-78*c9|)X7GzP+<`BrLin8~#xsw)Vb)V!4$ejL{wcl)#v^*m@St%z##`2l0 z-D9GpO_|4A;(-k1e%b15yQHld(WUV~N6OZ>7DxiJjZT3;7FCv|7fg@@<_ z9x`&|8+#nkIkI%C;Ujs%fGnkwiD#Hdo-iQ8`AB+?#Qr^zK)XxtC8I|21Oge$Z_@hS zgpoY4K&MNqVBtufP#}})BCTB_d7^<%lhy-~Ji$Q5^pEQOY0@~Jc%Xx&wM`sPIFJ$i zqsE~nSrqA|&tuL?bH@N#td|C81OZ4 j;g=t)KhFPL4YI<5v2M!JY~kXSEg+t!tDnm{r-UW|+8j)X literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_content_copy_grey600_24.png b/library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_content_copy_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..3b2aed29b5c647a34a3c76623c2b654c343af2c0 GIT binary patch literal 339 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z$oSE;uuoF`1Y1#SF?jaYhrma zpYV~xdnckJZ$|B5gD(E<8P`_CoxN{* zD_X_$KZoUuJl20_%Oz2e(ZN4+ zRFQ3rHw2MHj#vE1Vz61o5NCH_DObV=#&cR-Pr9tc6W&IB{kWI$!_s`$r1GtC2fTKu z=>}a~5!Nfcq3oJ#KYv}w{i;{n?$+`v*facO{K2{|S^fLktFwQDO!jp3b6Mw<&;$S( CTY9em literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_send_white_24.png b/library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_send_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..0167ac8291295daf62b3eadd02196870ee64b9fe GIT binary patch literal 580 zcmV-K0=xZ*P)uQ%IP?VRrKdeX#HFCWZJaM*a~J=|S?la}BuSDaNx}m5F;-&2C}(*JyeaWu9k*!%gcD!^dznGN+Y$vvzC}Yo0oHMgHbT6M z7fl=iMmVErf(fuz(fpG40ip>cz_6nELq7aZ(cDxtp#)gK9;T_I6)hUSfM5+bY0-?9 zKbmH=9nqZT3Bn-YibjY||DxH=6v80jk4A`Y`M0o|8;T~B0P_`1I01$@#bf$G&mRqb z0Y$TmN&1XG8ovOmxlRic{%BkR3~|yDO`H4NHn~04azT|w`c#yU2jl+0eyCS5>`M#8GbPt zKD~Pd3_-Pv1O2n~3%G-76)*Y)8&g0*O$QYatWi)QC$bJ#DeNcXZ=7ZsHN=Ot`Pyx-kkLfr`k|arzB>4yy-+7jY SX}CTB0000Mg{{G2FHun z?<6(s=J;R84OD{x9QLhHsZR@-dB5S&A2yNa<_j$LGamiPt8sFF#)0(vax<3fWHRVE zXS6N%HWYDf%)NarUHbH`$whO{%-y^BZuzS7{uT2bFT03sX=I-BzD~dDczWHH`x>&h zdM_L|xBIe6-S&YId(`zguZ-v0|7A$q*jj9x-B6Ib?`w;9PI8;hGk>cFSK0T4e~*4@ zwtkb`_~x0vN<(MvE4IBMrxnU?cm#ia?yuLt`SyjTZq*@!?Kd5gfdVQGPwytQ%rm>9 z8`fiAAH?YMP$K@+rQKzhB=Y~YFwHpF>UOf(&d;c{=jUY31i$N<6V)Hz&G`1?^K*lS zn|GEv%Wd6tWXi|q=K~pptxs1}n%&u`#xdW%k>S;wRsAA=vcgLhKdTEIFuFH&Qn`*m z=D#=08AW}3D>Dn%{NnhWE_>jS-NaSf&xj}fd&87b&}F76{odp2!_Uu^8Y1_u7Tc4u z>%&iD{)E!zD_wEZ_~zSRX5hQNaN3p|x;6iLm}Xpn^nuSSPi!J&V3&G zI908g;n`(xow@f)HmUBa7246Xxu*9Pe}ZT8kqb{#ch6iUGO=~;yY5+h38~7Z_t&2@ z3Kz9k+Mc=cB*U~0ga5m?1%$6Mx@_V3UWz+Gj=ALg=WAMDC3?%g7N2D?SUkVvcyyS? zSBtZJ#u2}OK^r{v_f@{7XJ(w4c}!K-Ve|FSRYx_|bW+d6%=5QAz^nDOvDMo$(f{yd zo&^1=ndQ5V&9PnjC7_5=XR)hl-Ifx~c9~_i3mKMO^;Vr{7^=B^%?f`d#w(S9JM^Bf z(tkSR<(?UC4azOq8%s66&zb7L@L5XzibnR5?^&^W%qzaP1vu+WKK4hG#lmZaotRJZ zKNhAL_bU?HA{2UmUgr3)#~@iJ`i#78LvKswRzJh~EeujMs%O3({bR^1qjJXe=pRAm z8FvyCh#4Z*RcKw!!nbopH@2YXXMQfoOGHKen#H3fs;36-+5E<&&PQS z8a|aqteRn;#qhN*U|(_f&t&!+Q9pmpTr$JHtYP`o{PRiwPB5NX61>wc2&mKgz{gYD z-3;shFvM$K&p!I+B6CFCPczMD{qhe=p8j%*HLN$SYZ5D1<^OlTZP!m`rWT|5lWU&b z=e-hgMqWZ;&Q96)wf~=NO8RHPcq)PKc!m3P`=~WD?423}(u$Xump1ly{oGvTnwi#K zdG_GZKMxs=K1Wv*9SfMrG3g!s#IcNKuRp00i_>zopr0PDc; AYybcN literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_back_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_back_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..4ef72eec99423c5d4f83227e34b24835a79f324f GIT binary patch literal 115 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1D^C~4kP60RiG2_15C3<&H0A&Q z|Ihd9Wu7|h-d41yp@_F-ZcDVc#LB3;|NKk4rwLrznlW+N(!?KWaSTDLrmcF&g49pOcWlL^)DudPQ?# z>=7dNisp`x+jUEsl&Hz=trQ8y=FL3m{8Fg1!Z6qQp%m(@GhOv@*HTcHiv(ri3(E4j k8+r?F-kg>3<@>$x0_uA^XphlbDgXcg07*qoM6N<$g0$^nH2?qr literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_block_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_block_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..ec1b33f0ea570391cdac55473fc61c0999d53505 GIT binary patch literal 335 zcmV-V0kHmwP)%!XrjG=rAbj z!Wrf{*dUd4Az^(OoR)Q=&Ov@sSr6x!<=_oXSr?u$%)uSTs-j+*;wA^RC0+}9ctR)T zAY4H~|L!j?`r~WCi>mjSr=9-u*t}aX@#suaJNIk~ejLs_b7`S}os0613(2jKx%HNr hp&LmQf)bw${sDammpVJ7L}&m2002ovPDHLkV1n|DlCb~) literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..de635e034d8a61e6ba9ef6ce9289515b0ad18ac3 GIT binary patch literal 307 zcmV-30nGl1P)Q6A_>}*LhnP?4F|f>w z(mS}6UxL~I(*lfvQdJ;tDK6!rU=5;RExKO(Q003T1*2!Dneb)d0002ovPDHLk FV1i@}ex?8b literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_white_36.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..046372d0dfa4dbfe328e00e53f471e141b78a3dc GIT binary patch literal 438 zcmV;n0ZIOeP)iliVF1F+faR=(l%gQDbU!4cWbE2o~(yLF;fOoIO+@FMwNTX(s#$3P^ej` z8X8#u=Jl~}fv0UyDCQ>Ml|}G6?~t$fvOV zJ3CbYrowP%6<-051=3B0x!{|W_%wL-chC~5{yCet@6l4Bi(im!r40(CQa^>rhj zTtyGSwRR}XuKY7MTJ4{y@^Atk*?D}j&pjIZ(5g$m`)YQ#C8*Fd957TedK3qF$e*&HlAO2wme~w-#hC^WnLN67= gp)iA>tbY>v4Ov38j8E>9F#rGn07*qoM6N<$g2Bziz5oCK literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..378272ffc15f451e392eb042f955e24c02630763 GIT binary patch literal 235 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+iO`a}}Ar^vf5AN4G!pOk>;l1IB zn#DO&4xZxHNG&+0yyEo!cd8K;0`nYs%$glL?>=A+nDlPf{o@~APmi~s?koB3v!~j> zS(WVPY^zL-K0P`()3*4h=jmPEt%Y3T*S35*J1Kjq^zX1OzB8|Fdv#&$rKv}!y!jRK za;and)5Cs3>aVIYFNBxNya&_Y#csE0`HNjjxVib1gL>yWMYp~)DLk9~L?v!`c^;qJ j`^V|}-m^Y`q~q7ke()_n^5q7g>lr*<{an^LB{Ts5m9}e$ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_36.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..625b827c44e7d15ce385221dbea4c1733c5ea8f7 GIT binary patch literal 314 zcmV-A0mc4_P)kgg)pim>AYHsfBK7ju zq!H)z-0OJToc}XD%TKY`{|dth6{^%&Yp=#4GYn%;_JqF@OQc+r)g?z%83;j!X^wd! zREv~JOdd4F1$MWb(;#7!4HD|@caPl}6FxM^A$IGG(Sy3yOPOu#8We44mL_gPC}*R% zT~X;khE-nS#}K@*f)P9Tg&@Bz(fSkUQPlB!rY{#Nk=21HkmA;40e!M%Zg5K}h;C|+ zeiT@deV0MPrtX+SU)($o9}E)jRKf{m^o@;k%5H~2;`fVCgd!B)8$jl7HbnQskpKVy M07*qoM6N<$f-$p&NB{r; literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_made_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_made_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..9b3cd43803064f22063a8c8effd493a5b1c5d0ce GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+iKu;IP5DWk01PNA!5Axg#*0Hht z(Es*di&JXBDSg3}jO${iXz+486|kSUU=9cGic_3f4&iV`$-ABEL7%%L8aQgQu&X%Q~loCIIhADn|eS literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_merge_white_36.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_merge_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..a2eb54bab110f4e434bac24abb96f5e20129febd GIT binary patch literal 208 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8LpbWaz@kP61P7dP@YJBTn}sP~z! zsFByeb5MrS$oZJ}^O}d>=I3;(9ld$?=WEZ7AFIzin8+JiIpKu4wr2auj8jQ6r&3H* zC8rDZ__Ky==f08mXDg>~#=+w)ET7pvngrUmL%(R z{HMxuFj+3}NQ{vD$C*ufSzqf9+^JtYyLzhhbdv?2ly>fGoXcc>`fsvj<(K0M<_hz8 zJ~J^Wr*k&_VdTANuzrDJ;Jx!6X6!vriWwHvoO*sI@92}&^Xt~UdC{Hk}*!A?jJR>)4GKBfXec?}<0&9upF*X8-^I07*qoM6N<$f?IEA=l}o! literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..e830522008b0a1b1f39fdde1156ff1bae3f955e5 GIT binary patch literal 240 zcmVHkAXPXi!ebT=lL4K1x)6Wg_MY91 zzt7rrmFO;X_oUmq$FIPH+E8b!7Su|rTTt3JU}I)<+1$1SJPXOxL=vhYuo3Q@z)==< z{b1(CNz*~H=m#TH*Ja}&F!>pnOOBdeCCh%W6|%$U`K_?;2UJ3mWl4Bp2(Ys-zHDi) q+wWiFtfaRVtkebP_bn*je*_=o)*|^)1w=Uj0000S3bFt5nS?tU*5U+ zuRv$a3fXL!qPq!nmZ-`S-6wEv!Im}!G@?dn#;*=rm4ZHT$3Hy5 zK#ky=d(UOmFsQV^o<2gJx=}eIwnA3W7xau83lN!8vECcV2)4w<^v@2~67MD11sAjh ztGUt}LA${P1=0J3E1eNGc`3L+Gf5t=WKEt5E{OV^X;qWQ4p$&rl*20-lc(iB^4yia zijQ0lF6anWaiv8;dol|xA!y6No&?ck78<-*{Fa&B9E#TSq3mYYuttQ*QZ*_=*n0M$ zV!JjJ9`z`_U5gAzIwsc`sys4xbSaS{W>lIoJ$6TM=qna%_I>f1qB5iXUVh&=cfY<* oSSx7G$evyZ)YnOH5*(G_7e~OF#v^w+0000007*qoM6N<$g3E)#tN;K2 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_black_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_black_24.png new file mode 100644 index 0000000000000000000000000000000000000000..1c14c9c44592e95983dec13ca705ab99a6c54f21 GIT binary patch literal 128 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1cTX3`kP61+1H5jHdYPvdOa3!3 znXv4Sz4PG@!RHQbn4&mG+#ttr57iP(&yMOzaz b3U1|4(wvBWU`oB#j-07*qoM6N<$g4eBf7XSbN literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_close_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_close_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..af7f8288da6854204dcc4e6678b9053cd72032c4 GIT binary patch literal 175 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+iGEW!B5R21KC-3Avpdi4K$<+1X zay^SH!@6{thMdKZi+L1hS^BMZUAdKCT}(HRw{NeWg~AlBHtr3jj>2B5kK^|J))MUC zlz7ydwCsb8xn}W?^r?}5wtsjdmvX{3=JbT!J9sKPrYmk={m|7^>A|Z*7j^D$`>}ry Zqi^Z9GQN4ct^!@a;OXk;vd$@?2>?I&LQeny literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_content_copy_grey600_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_content_copy_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..8ac80b083f62693e17cae7c701b1fb1c2f423b88 GIT binary patch literal 135 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1KTj9OkP60R1@0+q)As57?PoSx z;AFrUi2|JdW8ngaX&gvGK&O`f)#esG*c)I$z JtaD0e0svpjI066w literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_36.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..9037f94e843b77bfd389f4405035d5a89ec017cc GIT binary patch literal 264 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8Lpc~2L|5D)LSlLEP#97J4W-Lrmc z^oE5zvbvn1n<*bv@OviP+}~ZV+Z!+bw6W1UT(BrZZo(pmMim3qOO26>Wu%#`w=guY zMJ7Z&IrpYeS~~khkGSZ}TQj{g)-1dyUz$>tF1K)FTULFE(&79y_xMvY7#PBHPUOrz zd3Swfa+8F+%myx>#)t%Bb>=5_+rK*D!}aNMw;HSGM$Ka_$-!ro9^4RdF39QH z*rs82G{RYAcG4O}#r^dYjFp}&S9pqqo-P0I_0PO_VUxbC;gFvS^csVwtDnm{r-UW| D1Cwe$ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_edit_grey600_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_edit_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..f003bc9d334bc81c608d54bce11620626b1fac57 GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+iTu&Fr5R22v2@+KcuI&EeooTOm zs(#8p_CqI+WUXM(W`re$z@%j|D;iCndPwb?zDsy|k7uym4h9Be=9Q6QofDFQ P7BhId`njxgN@xNAVk|w| literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_forward_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_forward_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..65f73299f97c99039ae7f76435b665cf08cd16e3 GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*18&4O<5R21yFKy&yFyJ`i;P(IQ zT+Vb%7 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_exit_white_48.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_exit_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..364bad0b843bf6a17478979fb0e66915aa67d818 GIT binary patch literal 101 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZA`BpB)|k7xlYrjj7PU|_|fb^sd^~`LtLbIA@2_R9U%Rlu6{1-oD!MuvNGQX>sqmLdrH2qH8~<3YN()zIR{kRWh!ao3KJwpuzm z_~~&T)Or8wn(}$1e?o(X{(=YYRUAhId{R+S+z{!h7!G(LvY@0Q=#XeD4>mQLxJ*er z<8nd`TR+joCm>INPge;nZuw0gOW$!#h{+dM+Qlg!WO=8hY}D~dTjI!!F=>y=!z*b^ znQ=^(s!TX17UJO%5<8O#BO((VZBXZl$WSKCS#g1-Ei5j1W2S7_++iz)Lk5(!&(?(s VPEG8{S6~1D002ovPDHLkV1nDAZGr#* literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_group_white_36.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_group_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..25e443424e436c24bcd819eebb352e421a3dd9b1 GIT binary patch literal 236 zcmVTl*FGu z4)ilZQI}7Xr6bF!wCmv0FYNYE*yX6wuPW;cnn->$NjJaj6Iq|;`6YdAaLpSIE-nsl zTn&7C;&-qM@xl*jhNbxCx&6l;f1=)pTOw2a^JvuUoris(210000kw^damzv-{@%W->wW zUlB6El5*w3hB^KB@rVRH^@^r1-sObIh>0*5S`67DayrG^PY6rRp>-CB{N)NE3BnQ< ze6>I8Xoq00000NkvXXu0mjfmbYeO literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_white_36.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..d25d3888e1a31b389b8d3d47da45045511e54a95 GIT binary patch literal 350 zcmV-k0iphhP)U6u{wqFExpTXqxsMVGg4E1clKkXcRs|iijYcdC*iEMQ;!~kmv#I557p4qddp2 zaV-yR9Y}=hH(ZMk_GqV*jD{;c0|Pw|-IVI9TU_dz+X8^Cna3^;fjU;|=9_jdG*kg9 zOH+ly)Mq3ebqNSaR2W^fQZJMGxR?}qobfvgq|M-J&Vw7>w}^1Zbc}0 wsyqlPJ*oRe?wi|WK^rq|DMH70hE5Ot0svnshs5?PBme*a07*qoM6N<$f;$6_DgXcg literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_history_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_history_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..d67647c560782cd1817d8a1fe6466ba924894ae1 GIT binary patch literal 327 zcmV-N0l5B&P)_jM?T91pXt0JIFA7)R#gG$`_oPwmxS9X%3mB3p z@KvLj$#qv_Rj7`Rus>x3?_yvG^}&pQA666kV<3y$MS*)r$G|5XDGD6LhrdRLAhZWy z*_}c_jI;({t+da2ocU$lM=AgTX^vjVzj-6zmROnb2dbs~(^j5ic0>pDDE2 jzES4mqy6s}oc+sic8*Qfk2kwOj%4t3^>bP0l+XkKat%vT literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_info_outline_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_info_outline_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..353e064951788a29a64eef439284fd97e904f374 GIT binary patch literal 320 zcmV-G0l)rT_h)IX%8`!xx#?O($dW=BI;pgAmAMoJ&FVmpak^_M&10n8om%>Hp0CB z>RbH6BfRjxN9M~)&M4Ia$ETJBLQ^<<<3g$He5hLhidW{F&l zq78;P`5|=ls>YxRGDkGO4)Ha@UK+s{*1}DYDDe@&3c1kJ7>fuhJobWT>>{`#?O7?v zaJd6ic&m6Kxyn*Ci7xy1O7D6yV<~Ad#ZoSbb%oCVPWUuVr%YQDrkfL?gZZ)JBOfu SH&bZ<0000)o;J6EC(9O;OXk;vd$@?2>>}dEa3nE literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_black_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_black_24.png new file mode 100644 index 0000000000000000000000000000000000000000..da605a5a19a6840369f56899c68de52b65fff291 GIT binary patch literal 271 zcmV+q0r38bP)IJ2%uL;t)9p{%BV39DvuU|=GIiGgFQMv{d9^xKgHN#?CUlDSKNwI4Rh VaA?C^Ro?&r002ovPDHLkV1oGvbIbq$ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_white_36.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..6fccf5d09f041a62f4c831bb7038d59216d91a88 GIT binary patch literal 428 zcmV;d0aN~oP)7*pw6*!brO z;>wChcQR1etfOQBSPTH4;3^W?^LfE0AR)ugvqj9w#dIXk)a2GmiSbTF4Z1+Pq!7U-2 z_H!z=23Gr_Q^t7TP3tC8sAm{i=!e2rRpyU3o-myXeLd^8 zPvEl+XN0gloeD>_ssDQq3u+dqq-KS}11(yE8K8oCVJ;7?Xf#%)Y_4@o0!s84K>q== W1dVw9)Q3s{00004mTQN&lnQKr2S4Zoj2sFV!NULm002ovPDHLkV1n;7d{F=Z literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..2272d478c38ddb2a4b3c592b2eadee8d4e296432 GIT binary patch literal 83 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1DNh&25R22v2@)?K*o!=P)So4B g)u6(pM}&c4fy8~qg|k0wldT1B8K;fv1aOh{y5d1PRu~43dBH9UPL5 z6iT3kP60RiH8sDZ~s5{|9r!S z&-T)6^3n`m2OOlW$&Wc^^AlIr-(+2jG^i%(0k cC1x@(@N~yA-d?h_2WzfO{g&X4^9KJx$0|C;~yzoC=Vx_{4qo&Wp) z)_?W?M-MKV^nd=t%OAe(7n`y6^L-J${Gb2T^LRNUCZ|f3@vi^Cc8S}E_g}@O*WLg3 tNl0~^w@}HhaLuy&aD4vt7tsL>45wc?Tui^AH5KS422WQ%mvv4FO#lLLRT}^R literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..d474bd577d00d2aa045685f38b1729e4b2c314e2 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+i22U5q5R22v2@-1_)Iaz?{r|_t z@c(}UO&^5wG3f`I3NX5v2Dl$y{{P_r{X*9Y*v@e=cBuVzj-6zmROnb2dbs~(^j5ic0>pDDE2 jzES4mqy6s}oc+sic8*Qfk2kwOj%4t3^>bP0l+XkKat%vT literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_48.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..2642b9e09ec00be308649f62d9323f22ae2b6c6c GIT binary patch literal 304 zcmV-00nh%4P)0++mR7nD4pd~x$TQLGba6~{cu-M!3I>jYZG8L#~C$dSzGCa?>% zii{qBH_l~3H}Ow_R&mWIA6&_uY{DqeDkOK@%2_vI7ibl>$R-Q|t-=u5gh8NHSX1ob zZ91p^`0a>6o%RQ$Cqo6Qpk>-nPOXnuLHxL2AA)bf8YiVe5h%F;0000OCMtu*=z2v@^=eS1UZ1g)78&qol`;+ E0Fs_H=>Px# literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_18.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_18.png new file mode 100644 index 0000000000000000000000000000000000000000..63ef736834c7bc09d9ab5649dbfbbb64d2eaa431 GIT binary patch literal 163 zcmeAS@N?(olHy`uVBq!ia0vp^LLkh+0wn(&ce?|mvOHZJLp07OCoEw6vHoNI_y5cR zJ6`XXDpNiGU%7d?#3_R*4F@*=f3;(Z2!o61L24(@J19>frm@PzQ7dQkO3J8U? za7_?->m;oyPKIFLY|CPt74=p>b4rVACHEFUjXkN7Nx_i!83}`EZ Mr>mdKI;Vst0FA&qA^-pY literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..ac0f3948db014ae6862b315da6118c3bc840121e GIT binary patch literal 148 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+iXipc%kP61Dm$wTxIPkCr=44*4 z7hdJK(x>HqpoX2~X8p$9EC1%qxK)|8cmi|dA14KNr^a_P+8TeeAMUC9F(ZLbe8q1W)BT+HT?|6mfYva0y85}Sb4q9e04AL?jQ{`u literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_36.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..ff7d95706a5595c99a51378b85abcb4e42532997 GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8yQhm|NCo5DtD%g{h5`&1-MsIt z?Ftn%c1;gXn`LzFuk4=3OFqB9rNL5}zP)TOCC0T;b9Ys{OLrrXCFaMRCqGpGG+9_x7{vAAZq5R2RE zY21&~Xg|JO+wtWr;6tzTF7KRo*&pyhYCjM3toMt)QZr!EgaK7aw0crl1<+K|Ng#Z8m literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_search_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_search_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..faefc59c8e574774fda7a43bcb2214bd109eaa1c GIT binary patch literal 247 zcmVO-uP3I_MSsAi{+~}>Q9~5;lEgY)!cb2%BmJkTJbGA{{Fokf9Dnd|6jvz&Sm;%kEEd3fd&rw zs#aC&Whn;If@LPA%o8_piu7>oK46mO>*&NhUu8mh-3DPLzfL{l#f|zkNs10rm~z|F z8`V@Fa%(##iM%vOI^H7kfBBMlnHJB0W$Kf!xVv1a-x6N6MP@h0&#Vhw6MURMe-3i| lW%ahQ``7c>yRLUMwc}2wpSHMuI}_-B22WQ%mvv4FO#rm=UJn2O literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..dd5a42f55c338da20e734b1bbaa86d7b53ea4ea0 GIT binary patch literal 252 zcmV{ckkrF<`~X@e{>T@_r}74_kj6Ry00004}z8AM>Y_286pHlh-;AK$b|v_ zzAH>C;hkH}!2F6yi&7I?T=BsdQ?A)2*($2~UBY+5jGt!ojZswzI>0+Lrbaom!W8vH zhb1~Zqdr-Vj8hKnpx$WZbBlM>Ze*NtsE-QLeA6dR>pa%NCP?t($j2h=t zm&5>d9v)qw27g0sCe)kICUJ~<2#-dno|+_nCU+l2K-E zNe(#`nZz2e{O*NShn&g`k-7`ajTncV664$8h%I3F$OGgBe&}s+R~*O-PSb;4kUT(M@D~6W!do67FStw_(R}2HrYMS{C?<9Qc|YI1 TReply00000NkvXXu0mjfa%qO{ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..d1cca6f0a0a84d01c22758d7a20046b090ee0cd1 GIT binary patch literal 198 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+iUQZXtkP61Vr#JE*au9F{^qwFS z8o(`dR7$CUZQq>|NA8dhoNmjnvT6H1*?&;&^Rn7Ur<#vFnR8FL;$qE(2wNqEORg~= z9QS6*>=e$;C_KlY(fRB?7f(_05=+w)EN8P9TvM2JU173hYJ-9v$D?KiGXYD3-weAv x*rY@EI~uKc?;_6mVB%3$CGP1A&)%~B%lLKT_f~IqY$Q`@<$b8J9dcetKhA!xO=1{`t^{Z z!G;5B07wQ31tb?$@=+BZwPm0%M~g0rf`|w+++f!t*RCdgs5aJzsFS)`t8H)YPDaVn#!5N+>1(a#4511VMmA>3A>#(y412bOZHl7zO z(-NIDZvB@Re#6|w{rA1IhE;>>MaBh_ivROJ2rpq=@x)%yHQ@7#1sxi%4P^X61T2y` heb~1gkV#=+ILP?v)rarvB7o*Hc)I$ztaD0e0sy)SE_na| literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..d146209a5145962cfa3226918807fb663d2c7267 GIT binary patch literal 131 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7~ThPZ!4!i_^&o609!G|JDCLW>R0E zB@$rzfKlM-fB6Xu7?;Q_nyA4m@N`K=MMHs9q13<2G0Z3Zl&)S@Vb}iFVci(~H*k$- dvd9Bg24TD2RUWTqYyg_d;OXk;vd$@?2>^H7D%Jo1 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_36.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..d83e0d50c3dd1aa384568f658f815b35819462a0 GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8iKmNWh{y5d1PRu~2?kC7U;UT= zr_N^cXMNj}ZsyAiX8k|Xl(j>y|G(%AHdBGz0OmV0r(G!x=$+p70eQYbmvva!KO(N7*idOe<+q%wP5*BkoyF@(&fw|l=d#Wzp$PzEP%k|I literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_grey600_24.png b/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..d6cea3667acb615398f1b2d9157d66034594067c GIT binary patch literal 256 zcmV+b0ssDqP)ep3Ta(^0g|FLfCL`5XYr1l1rx-2W#40000_3jXM$Xr=X;u-(=$+=p?pXDw?0dQEU`vlso0* zdA>~MdnZ|}a_K;?hMpz~crq;DB#C3M_^{K7{|JeJE4*9lz<-5A&ow3;cstUgmBg|) z?9YRLs_i}`i4$DZ1hx|Ec&Q3Ui9Wun!eJ|XR)x*P2A*reeUcdAyt39iO`>@L8ae*^XoF*Pj zyZkh7Ub{XL@4QGHYZ5VC@2&xYC#cf}!13}qb1co#owXXu+ ztYpS~fIYLb1dH;tFT zz2;wIYCx29Cvl4hF#TPz{h+!vd#T$3+p(akfyB*#i&zkgi5mou@u1B#OYrgsKnsnz z+Kc|g&E`w?Zt8ZxR$M_|>P-9X5lqFj$dR5jE`mEv`I@#*87$`;Bkj(?wbnd?t;=ch zeiL~{?YOJtp!4y=f6Rd@cvWn~cl2a7{|8yIuMqOdjdereUy*tT*z=o! + + + diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_back_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_back_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..832f5a36172308b2c53cefe5098f828b0b4eae53 GIT binary patch literal 131 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}a}tFHaZ8kP61P(*hY81Vs*P33^+* z?}ShT8^Z?H8wU#67_vB}O4iveF8(Sxb9MQ_Mduf|_wSo|^4HTw&d$`?K20o~LPkHI ef8TJwoS{Rs&mwvukCYYAR0dC1KbLh*2~7ZsnJcpZ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_drop_down_white_18.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_drop_down_white_18.png new file mode 100644 index 0000000000000000000000000000000000000000..4c6076df77463404d7163c9929bad5798576c49b GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;lc$Sgh)3t!GrM^i6gXHN+!Ft< zyz%6wgzzGf8m{hg<~baK7i~0n1e^UrcB-xUbawM9)9}#zn5)@-SM$qEFA7|Y7jyVu Ve}1-8%O{{|44$rjF6*2UngF%-Cs67z<`z;jXwgQzp9mW!y*j_L)Urzog7Tw4mjnNHokh=!9i6kv=iUE*AsiY@ zwbM@HiWxhO*^UKm%uv_ljVks)@>< z4|#_uDE9%zam2Fs7-22CKAyk*E6j4L75z%{5Txl`6KOW$3$P m!j@yUWljq-lHR`nPQW+BD)wYfX<&)~0000zfbBJi3%L}bpQ6wu z7sV{>vU}Oxv@~qHNm}^zmdorgllNBed5(eq4<=Fpz+C{p z`n*v7JO2WJZ)F1-{s4T4%yXia4ZH^Y<@%cWfAq}(ud;w^mVk$A=f4qj0SjNA4?G9F zmqg@)vI*dsG@#@Va4#w!1RcP>jWlo@@TW>-KB$@jZl!@fU>K8M?HfQh4U7Qo_`IM4 z*iHjuKr=osxCz)v15-dPJ};;Pj?=&ruo<5hB!ERWP>RnBE@lH$z~%V7pppHE#(*2~ zc|j}tPaXm8$L9qPvR~64U>KhlyahZ?11-QzB|86^Q$RBflpFxsk@=tl*t3xaf*$}M zm80^TCV;1cG~lWw;88?A=mF-goDT#8z?mm&=f5@wyb!X0x+%b#`7i7Oj$FzHg00B> zZvgJ(9lQnr=ofrAy8vDac|hVFfVr-6&YROS2k^5C#SXtK0uvq8jL)iLf>mCn=`Az*0d3Sjg8z-K*atBu(W8V?>T@P00000NkvXXu0mjf?Sd%& literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..eea1bbf04b00cda6609939c4abacc4a5fecb881a GIT binary patch literal 518 zcmV+h0{Q)kP)wml?{hg-d2ASX?CIt}{01*!W5f1G9PArhGh07TRn2oi~O$fOP2xUA-*Cey4W1r{H6g^uMpSBm-Z9)3PAN5 z(Lj2(=O+q4^S?8*V+&h8(O0ciCeU+*~Gn7~e~>pSY>0H}`%>>@`1P#*`tjDQI91K6*@QSfX+mH+?%07*qo IM6N<$g8G}=Hvj+t literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_white_36.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..d5022d063e4355cc8fb30c2e079c842d7c9c973d GIT binary patch literal 778 zcmV+l1NHogP)J7HS8wFLa-1OG_e(J{SOp*RkRQku@J%1!nDRr5wH{O)7lsn_IDC2Vr;Bc z>|&yw76ufN7|bIQ?`1E?uX-dax7g=YdoMG5NM^|Fr0CbLU!Jj1NwL}Uw+DvG+(1y~ z27)p-5R|!rpv(;fWo{rSa|8KFF3>5asc2BINSd<>)Fg>sku(QDle&AgnIy@H)dNX_ z_W4MD(0xLh)Lp@T56KUzP!}Wx`c7K z&(kR|y!ZQyXS_L9&|AIMK?ka7m;05F!U-X&CXfy`8YL#i9j3>)1` z)+Y!(bAv3&!I>rWJlVNS=$#YfAl1+uSV{Iy6Z+x+IY^c>#2npyO?Hn$Y|Fm^4f7Zc zI!0){cfYdwFG=r{y)%S9_VS``7}A2csIL%O>fvp#N#?enB(&fIIXL34*!CZ!G4Um0 zN`u@SQOl5?0Ed#bMM76K$j?!=4JrLO?19)34f1hnbXP}{>|7%BfdLKjaVm6YAK^L- z%Ja1dJ)qDa7soupTGEUl?P874ISq1h49JpT_NSzALMseukc(qL=6Okyw(*wGZ3+!? zaV#hvF-O`Q>1A7qx5FAE8sy_>&;eePc0KGF(iDXNIXN0MsyT-AiM<-+=NORY2-0y1 z59p!bXwWFjmg5}_`kz%a$AU(D96zYwgy*HF;f(jc#nZUjJH%oIF4` zC~^WtP9C7h$paKQd4MJ;asow82B65v02DbHfLzlD^+A2mH;fGG#FIoUDF6Tf07*qo IM6N<$f)4FreEGh#=i2 zxUHW#j;ZlmFB~yTpC3Sx}?~Nic9mw!VXE%t4-O|}Tsh_|+P54s)>dbrr zidFQ20(vVbVGTk9pdd6u1?s{B?p^l`+zDx(acj#Hu#H<)l7cYeNZ1sJc>*koG@S1d z!I?N=0P(RwPMz)%p_8y#Kp{S-Sj5)v5kV&^WRQT%Q2D;s0U^mDyCjevmSBfHh7cVH jZ3Zxa0SsV(e*t^~=a|RM72~P_00000NkvXXu0mjf^Vpp> literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_36.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..e1831d7afd086dcfc741a496d058af3d0308da99 GIT binary patch literal 553 zcmV+^0@nSBP)Ksbir@OQBE-g|t&k+Ykz+ zv_rwEC`K3YWfDSS5J7RvWL_XcKqYFppN>MvIXStxmwO?<=lKUdap+5>QmIrbl}e>j zGRKXZG-J-9Wt+BCRc+a{Y|)qQxnSHenb_~4{1ro{d|_SL)_iW#>#}--+KstyO|7k% z^}hD{fL?Las(SQ?8(uyLC^P13^={64vi*ZH6XrFlAAKO(59m$bE9xH$9-8v0VFP+~ zsHo`BYrtDhy5x~1|0(JlL*+odW>xLpwjW$JqEnQ(%e$_bmsizYJ$r#Zu_nI}QN!c% zTk&B&=mn1z_eM>icNF(P_imuq{7zFq{AzF~=!Cy%8i+rA{68pj1)2(ii!u?~%+L}b zZmWdrvtU;=W`?d^6guO|>85IXU^O5DfI3g62s-|^{I^FF~F-L?V(yCEW=O=9B zb417|EjTI~@JoKlw1WKR;N}vQvpae>w!v}f>M-hs<`NyOS00000NkvXXu0mjfwpIZY literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_made_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_made_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..7fe69410515d6b5cfd7d10ed0391309767277b01 GIT binary patch literal 185 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0D22U5qkcif|m%O5Pvzcu7C|)?u@4x5A!vlU#-yab2 jQ~IyMr?fs(_#IPkke^$<=Vce5TNpfD{an^LB{Ts5nP){Q literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_merge_white_36.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_merge_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..01daecf6567f5d26d11eee3ed02d30072cdc1118 GIT binary patch literal 287 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawo_V@BhEy=Vy=usJD1fK=q50P9 z5B^E#@*nY4=vF;u^=os(+pm_tUL5k8q~iHc`MrCoplhGVvrtzLk>!UbSn#%Kucyl?0B;N z8jt&u%Mn!y^Oc2oFCG7Gc}wozwVzAv+*OjZ=j0Z?SzCPVxkR+Qi;2R1u)XrB3N9M@ TPaZM>eaztL>gTe~DWM4fT)uE6 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_missed_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_missed_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..dd64489aae8f16d87a7fcc57270cf88bf7a8574b GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DnVv3=Ar*{o&w6tm3gBtG$Q_$f z`^N8JsF+fpN@0P5mEfoJu)O`7)ArxXF`M1Gt>F5Oqto_3WtaHu?qZYln)%%Rvj1!a z|2pnE)XwOyWK^4A{^8%lD<`FII4a~POmw*Cpmwg;hC$$jw8FtXjsB0CYPdC6KItwH zII+FK$0D8~PHh4^15+h4P+tNQSo?$D_6ZG)Y!VMR*B#9Xp7p6p2k1x!Pgg&ebxsLQ E08^??cK`qY literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_received_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_received_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..807308d9deec4f180ddc28d9639a905ce00e8c01 GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0D4o?@ykch)?r+9NU7>F=)%Ux>S z9{gcSYe&G=t@A^bIA+!w|J|d;lFY-a6Je r&`O!|;dh)&{M-fItX7SN&(dYyKJatBms|A-=q3hFS3j3^P62;3l0LOD$N=(0Aydxv3a1NO%A-5V49kkQ!=X zV`%)ixtjF0)a^NIzfT&=3_}@<#bU8k$;l06(wcI^K4~{{!wzW=azjYkD}h|FPQL}Y zV3vL*xgg+~w1(VpOxmv85YnrTksES+&{fCC9j7Gf82Mn8*e6T!#Wk@r`JzB#L%wJb zYcnT5u7H4zjb0wVlEO#(-afhJ{~L_owyniLh<44m_hh=0)JC~(EtGz}i`o*rY-v?y@O z7&HsExZpoDD~cS_W+YkQAr(Fol6E6IIG(V_N51l%CO?U|VOMi=rhWlQl3!NbcvwOJ O0000S3bFt5nS?tU*5U+ zuRv$a3fXL!qPq!nmZ-`S-6wEv!Im}!G@?dn#;*=rm4ZHT$3Hy5 zK#ky=d(UOmFsQV^o<2gJx=}eIwnA3W7xau83lN!8vECcV2)4w<^v@2~67MD11sAjh ztGUt}LA${P1=0J3E1eNGc`3L+Gf5t=WKEt5E{OV^X;qWQ4p$&rl*20-lc(iB^4yia zijQ0lF6anWaiv8;dol|xA!y6No&?ck78<-*{Fa&B9E#TSq3mYYuttQ*QZ*_=*n0M$ zV!JjJ9`z`_U5gAzIwsc`sys4xbSaS{W>lIoJ$6TM=qna%_I>f1qB5iXUVh&=cfY<* oSSx7G$evyZ)YnOH5*(G_7e~OF#v^w+0000007*qoM6N<$g3E)#tN;K2 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_48.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..777658e95515ca47c9852d00621e2e6d45abc5c7 GIT binary patch literal 894 zcmV-^1A+XBP)zI9LJx5Cecy~F=}h8lwKtS@9n)MRxm2`AkqpItJs@p>)C(tu-V-#=CId=UD(s^ z#Zy@d`v;fOn~Tzu?OJHHNtIePI-lk`KN@Bx3G-g)`+Uz|m=FBkykXu`7K_DVu`~_~ z1Z4r$j3}CsFA0vr7p4ddb45K=_{;=>kNJmsIpZVU0%^)LLWz`4fe-nOMmgjIT>|g$ zGtFS1ZXE(|^ApYDN8W0_z#v8Txj;7;?6E~Um_R#sF$;$xalZoX{D6r(A?{D$E~c{O zM_>?haY%a$6fv1Q-U9oW%qwq!3ryzRTflV87q9|W;F{;GFv0){qSYiAAj>K*xHezl zfJJ&yHS#`7{A#YiA58NG$|F%`I5JV-9to7sbaLM;flIzZ1Lw!X3#^Fu{wYByi=R|$;R}qoTB8JI$kiVUUtqx1 zx=B!Su6`5*yii_yR9b4GhtSXus6)G54OU*Fzb<9Fuf)`*nQG!IEfB;+M}w za~X69{6e&@G0KTnj6*#FFeADVZuofoh-l4&E`cLDWuFO3wP#-rPc_|?^a;Rylnh;L z@)wd48zfOOJOnKQa*Rac43Xn8&v?osa%9ANUyhGPfeM+%FRSSkfU`OkhV}j2l~kBT z1bVSYwP7Nn+I` zNiohkFLCTaw-vAgjq*RZ@U(}??0O4qVKTS91=2W}ibKjn!0?Ng1(Y9wI8QK;$g7)NnYYA8~X1E8Da2KG_tL8~I;lb{)sL*P=iRKW#E4XN3@;;S-4vaHz;G@*R!xbNBF^E=vc14DCD**{Ec)-r|zy-+~0Wk{nu%FbU zK&%z;il49x>+ljXAi^0VY#<}fh?WjGqJmXY;kZ;lgdecVDnv^JoMBf|d^X?};te1~p2} gXI6cCfWAH8HxwM=FEv&Fxc~qF07*qoM6N<$f|{J!F#rGn literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_close_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_close_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..b7c7ffd0e795ba76ed3a062566c9016448795f7a GIT binary patch literal 257 zcmV+c0sj7pP) zOA5m<3jYBNi%A&<@ZO?$P9};P4Y5CjG5$M&YXI45J{s}~# zf|&?x1_gn4B7+hS@X!l}&!voFhmZP^sujifL@~PKMMM~{6xH}^g$q7WOzwCQ5vHTU z6`v~H@rlA8e;CUh_(b84zg=+ih`wG<)HiJjzSlQx5#CnjMR;A)R^jtaTa9;7rSy)7O%~`cm?ZjXImW?6TYRT<;U^@VKiSj`soFk00000NkvXX Hu0mjfhD&W| literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_content_copy_grey600_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_content_copy_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..ca625985998d6d9af79db16cf01f8701b0acfd46 GIT binary patch literal 193 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0D4o?@ykch)?uV3VCP~c&?;Flcn z;aQN(8G$GA>bP0l+XkKh$cmQ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_delete_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_delete_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..484260a9714419020b6cb2e61845b3c948e2e014 GIT binary patch literal 142 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DP)`@fkP61PXTuo}1aKS;Xi@mK z^PpsXh6iiO`_le~BTuB9l0B@o_tzhE+t$EVf5=NJV?iSun3ylClKteD;|8}i@)k#f lT5nfbI2x&Q-tkkp#Mp1@G&>>ctuD|422WQ%mvv4FO#q&!FE9WA literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..0e89f6c74b06fc9b820f7c83cf06157c27acaae8 GIT binary patch literal 281 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0D2c9mDArXh)PVwezau8tM+2dei zo!C&IXLoo*U0%roVd)AN-z)D@TPwFJtW^1V(7BIGPL6NpgYYdg1TQGqANu-}vH$hN zb!o>=w5NJK-nHP+uTv+Y55Bft$GxZGf%1IT`QLs79+apIU}+S!__&~BkKmoRg|QPB z_RlZhVe|Lr-B-`GYrH2eYB}DKG;_cI)fol{PfGUQj_h9Jx~n0F@4nI|%bM;J&*o$b z-jvC{Xuho@hwnC2?1Qe->}1_dVmE7-1g@X`e3mo!jb|5_wpngb*b{xgtX=HGS<8h# dPCvWD(0kMKnMdBWM?k+ac)I$ztaD0e0sx48fIt8M literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_36.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..175000510d4d2010d38fe000b55e9121f01a6c1c GIT binary patch literal 362 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXoKNz-Z{{;uw-~@9njNS%(}XjuiSI zOAq+fBE?hbxms;&m;WMxqSjWjzc;0qEGLy*t10@deX)~w)zs5wFSq!pn`O+meKDh? zYMHQf$$2>wmAMmN{<-Kl|7J6v=kjE$jgGV5IF??@oZJP*~@3M$%Z`7U+NVtYie`5P-Z!gp_9~-BOI9%gp`*!`t{^yCcW_% zejFinp-cM8RJCKvOn~w#M}hJpK>6;Ag*tBC7n8O~=t3yjxE1Y6mf<2tmAPRFIf`>mkmdkT-k(et2w>_1+?Tk$wCz`uz9XZ`=3&(BQG1zl7}p&_)JNS3j3^P6T$m`Z~Df*BafCZDwc@{~PY978G? zlN%ZWKgf5mski^P@A&+mS=aI~*9HAMY}L0USsB(|s&9O`k8?Z75KmV>mvv4FO#pDq BA9(-( literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_white_48.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..c1dcfb29024fc0eec6fb8d2135e295b5205f1323 GIT binary patch literal 109 zcmeAS@N?(olHy`uVBq!ia0vp^2_Vb}Bp6OT_L>T$m`Z~Df*BafCZDwc^3*(C978G? zlNlNV5B&dc&wTj*fBB4ajKP1J`;5;VNZ`w^TDCoqfnmn3`o>w)@0Ebe@pScbS?83{ F1OOWIB9;IE literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_grade_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_grade_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..d65f39d7cc670fcb4e58fded264e2d66479febc2 GIT binary patch literal 479 zcmV<50U-W~P);;$S)#5e^P1aS=*`(bN(+BvFH?ClNUa zZZ2uyQUnKu1VVolZfNN+qU(ll9CmpBvgdhv-$A&~M`}4>NRd*Im}6GKp^G9v=~Pg- zOWA~iL4<9}wg@W-3{f$lAn=Ncm+~KHsdh$w<0;i1%U{I!LACE3m7mB^Z%qCn#7F9F z;>j=c)68YL!6QzRG=q#V$ux^>(adKSnP!p^21%17j;Ft4m@F&g$Wy{qi99)0$TF;Y z#8|^Gs~l4!+E~C3^F-Ag9{2fQ_q0E*Q^M6RuIb+qRk>h> zMmcgcdLkEWQmepC!h{*6K&=hgBSEcs68eK~vefF3Ev~TV9ck6!BJbJLFIzlh*ABOc zs0j{{VTWB0WQ*67J>$6c!3myIwk|ugQ(}W&8Q>BhC~{af=;01g86wI!=hV^?kl(-< V@30#FP167X002ovPDHLkV1f=w(v<)J literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_group_white_36.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_group_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..7f0b7e903be85232eb4e5bf507062b025dfdd970 GIT binary patch literal 417 zcmV;S0bc%zP)DsmyKX&RFIUQSSD+W9($^dPS;3(#Ef(97W=l3HOp)IVgYe^RIZWgqh!W9mOT z3^#(48wF{qpQE!0QlkO+<3+WfqFQi{cDW#NBDp4*0%mlAm?+B&J00000 LNkvXXu0mjf8A!p$ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_hd_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_hd_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..4c954d86f81d25f57447ed088b5e0974b94da063 GIT binary patch literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0D37#&FArXh)PLJklP!Mpv>$0_J z#ns!%iK4ImzcoLolf$O+?x%F>vxZX-B%C`8Bn%HPoYKJRyzfur`ZtoSX&wf5x#x5o zxX<0PprL6$$D^qsB`32V$tma=u&v#sF!gujguX1{CEqnyJe_oPe&&>$FSm8^Y2P+w z71<-o^7j0DEu{^+m`}9*%WV1dw4HgjuD^$%I%Cn&rK`NGw1947@O1TaS?83{1OWHn BP<{Xa literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_grey600_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..f7dbee156ba558ba6dbb0993fda637c525ffa56d GIT binary patch literal 440 zcmV;p0Z0CcP)u%=iXv5-*mUS%V^L*;$tY4MDR9N7;$E^wvY+%T zw3Nx6`^d6h@?j2qlRI~hp|I(*+_(~SIiXA*69a=R3v6>n*F`ii!=-E#WNT+ay}EhX?p1Hlnc7O|xp6vo;RWU7yAS=JVOq|`gc>RehH(T8fJDUiIDU{OS0s}Wlurj}q-M8Bw!jzA18!GMTfmg literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_white_36.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..82db5427b7613252c64dec1dbb782f4d987a0cfa GIT binary patch literal 610 zcmV-o0-gPdP)Xi(=JuXxH$ zG|Fu*hcvTn@QZ(S${S|T$%E1?Q^U3smPjQDTHrfz`^KYWKv{NhZHsZ=paL!WsmVis zAk7-Rim0%{JUKF?NRc7OJ)W~gM6XuSK0qUEa-D?H{C7b`Q;FG%;`RLP?( zHpk~4B;6lqjqc7UGK8|+FeT3EZnYm!f$k2NM8(_`hjjPA6_llg*?Y!N4!g=n%ziWO z2HK&Ua|z|R%j{vc_BeE@sTa?(T5p7I1ejafh>h-1P?V2A6s0J}i^@GDwxDiNC*@ zOcHHv{~vp~(hG)s=_fz=(xB&DX7~8#EOepm%4~M71yP^V&8afwq^QFRPs#O&WziZN z4UrT+aD&6Gx7cDE9N|VEDJ1%=Yi)iOz%L$dd^zpuQNIG1%1&5e5Ws}}q6r6>2GDD1 z>GarL<0`= zE8v`H#&*EN5m|x6~GOhr87?B-Fd;+*M%6J}dL#@CqfM=tO zA;96a0!IS+ql_;B>uUuz0zQv2egZ766<7lJG5$!0W;*^Ja8Pa_B`W3aTK60A}7&N@-^J)Tfm5;;}6^lcqSUrQ8Ay`*{c8^k30++mR7nD4pd~x$TQLGba6~{cu-M!3I>jYZG8L#~C$dSzGCa?>% zii{qBH_l~3H}Ow_R&mWIA6&_uY{DqeDkOK@%2_vI7ibl>$R-Q|t-=u5gh8NHSX1ob zZ91p^`0a>6o%RQ$Cqo6Qpk>-nPOXnuLHxL2AA)bf8YiVe5h%F;000022NX4g$Gh;r2I3UU zC}4AjSPu(ixIwI-i~@=>;)?%*fd#|^BPhd-@r0NU2I`1i6z1DU)PjK~qBKyTf@lN- zCy2s8fg++640I7Wl<`GYIEcGoz(-^U3JfE>zYypm@_+0U8C+z9*+p(5%4UK1zv(Js zZ=k^ch-xrUL_9KT9C*VMq7V#ZxJHzW0~N$&*uzfo7172v3S>D)tf9gJQ}~FgQJ{|K z@irKcxri5LQU~VfAvRG_fjnJAhY3`QO>%*_Wjs2dSVB8ak(i`~wix%~<)U?%MJ3oA z7ie3kxPZkW+6y&o6w%94r-ydHP_ma_Nr*Gbj78j570v p!{d$?4XPC6k!Bt+*lWOGzX87wDYF(rDzN|n002ovPDHLkV1ir08p{9x literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_message_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_message_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..763767b4f6f4e3c64cdaabcd7bfd2197363812d5 GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0D$(}BbArXh)UiRc_Fc5ILXy^N7 zhMY%%#f+}PmD8jJRd2HFmRazc;lCrB;O+J{9#gkFcU#0Nb>3fa&US8b;5=)pcwr@z z9ZOm$gW?8>2^=c_m6)$I%I{k=wbq4g3DXzvZQ);-8rm8EdYe5+Jg~X3i@T)2=D^~v zC(H{3-cI~1-Z0Ugan2vc4WFzJobI0RS?S51w?}guS>HXkI1mvIbRL7JtDnm{r-UW| D48%@0 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_black_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_black_24.png new file mode 100644 index 0000000000000000000000000000000000000000..fa741be1c0e71d611d0b63c8f7d3c210be2eb581 GIT binary patch literal 454 zcmV;%0XhDOP)!_7sd*(?%MX;je7rHyoQ zC?WpA*X8gV?4jfr&l!Y#zWe(mkZ{cVk6N^D%f!UMeG3YA-bbOC_c~^3MNc>L>6`P- zh8AWy|5?~MK&*?**0ioCM26VP0)4IP+Q|}=EHI`N(HGe%MJ(kBY7=S`Y7=S`Y7=S` zY7=S`N)f;Fgkt>?Sz_jX2;sJreUTwfNVzM7pQdgkgvV0eh#b-MLHNE`WQNVAQwxt5?=Ldi4JNv?e8W`ZH^40M<}s4YU)Gn(=?Nztv4@ z0;Coj$nh5G7XHoNx=EY)2mrjoSwR<(Dr~{OYpwem*R)7FZwIaBE7EfcHTUfl8KX>v zHzW$_3#;rP$0b1OPk+ZLq_emXpcUSq!CnI?*t=}E_i3(Bu#;>c$2orQ8I5+54dl4t zk>kmH0-iVD(6@j;H`BuH>SCP*g@vMdHj v-!T&5!~yB+=7Dewpg7AxIVcC^przg~#hgjG{tg#hjv@%| z7X@p1JZNg$v`N1#x4v@>c_ztxnR!Q&3M$B9;i48VK6(idB#eSWm>>i6(t(#6TxQW# z$n-Nx#2`lLL&hV5E<l+u>^Xa7h#sa4f+9MUo^@Nyrg=2)9~;2Au*&nPra{7d-Gu zf&?EtaLy^a%n;QnbbV@><*euhV!WZJS5BDEnxG}~pmwKSo?w@I^3@&NjHli2*Zv7b z$zn&@;u%prvYGr~zs1$0a1$cJG&h*l6;nhAQjx1!G_Xe;EBa!GI=yDMfmN*=_0yOo z{AoUe=GHX+Ca=LmJMX6O@3iMT(;}eXFjLkLS1goM$|5ylrEbb~iTnqeQZZpQE z&7jf!H$2&_HyY#H5dTfoinCiWOt5U#JRa%d53Re?3NCZvFLL%xp%ksWWW~Q|rk3dx zN|q)bCv2yUU(zI4w0l!HNW<^jzlxM|mc*Y??!>m!{AUH8@H(|njSwf!u#-F6JadK3 cwV(|B0Q(+KdOT+vSO5S307*qoM6N<$f+ZvLy8r+H literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..f49aed757118a941b567629ec217cde1aaf257e8 GIT binary patch literal 90 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZA`BpB)|k7xlYrjj7PUzopr0A!jv*C{ m$r5W0{Noqkjk>0hJ%NeAb!~d=tj~okAZ?zmelF{r5}E*xz!xz9 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_people_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_people_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..715b49a3c80bde9768661e90b0c900bd9bd21354 GIT binary patch literal 294 zcmV+>0oneEP)sxs84;=(F?L%hs@XJlTRc+Djj4b73qE~{K7Elt zd7J*EgO>fu2#SZ~P(<9j_~8fhr+$lo`v?^*P+hKn_N^M8Gz=^33b4q s_&Cen-KOtJcrxAp17096_#=c6Z|*cby7*m?Z2$lO07*qoM6N<$f`5pAdjJ3c literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_add_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_add_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..7e7c289d4971337ec3693780d13b26c146c58a5f GIT binary patch literal 329 zcmV-P0k-~$P)95&=c7)Ex&ZntsOymfDWHiA zg$@)`eY^zFie0;oB?c^qK%8UTE4gLto&GPuldssShyXo3?#1bOU!tx^)93lHT2bFewlK`St_| bKmdLLcf8r0$|reu00000NkvXXu0mjflV6Dp literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..aea15f0be51cfef4c218f7362a2ab739ac04245b GIT binary patch literal 312 zcmV-80muG{P)2L{wR9-4cM#mgMUQ0N+L8>tf#7I2DT0U|p#LsmP?Th7KCX(*`=K+1-Kf;9=TnnZ^wzm=p!Y6cx1*=0_oCNQN+B0C0DD~V-AipxY+Y;al1 ziUOBhRus78vSN+PLRKWWjATVjNtKem>`19HRuhPrv&#c*HG_zhlAlV(wACbHCM?Ox zSumon;6LG*D{h#vB4f*zj1~6`x#UPT3>dP(Wz97w+8-@0c%`lv&S|MWdOWkQC%USK zGd?)PJE!ua#}|kCq$?lpu(*{E85VEy!AL$B$p<6(V5A@j{`dxc?LP59k;@bS0000< KMNUMnLSTZ|QiI(9 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_library_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_library_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..4bd2898a83995e88bee0c8105c402a4f9f3a30de GIT binary patch literal 309 zcmV-50m}Y~P)Iwh=taIULXwG3*IJL6f508{ zlE5Q}v8S&yz*N6;1HdgZ zXzl?PNYXtI91H6`*4aRVXG;Tc{`q}n zVgjGUnr@HBSu#Ovz+VM&fgayXpeYRm+9H7acW(lPtAN=DEYOPTdVo!v00000NkvXX Hu0mjfO`3oh literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..2642b9e09ec00be308649f62d9323f22ae2b6c6c GIT binary patch literal 304 zcmV-00nh%4P)0++mR7nD4pd~x$TQLGba6~{cu-M!3I>jYZG8L#~C$dSzGCa?>% zii{qBH_l~3H}Ow_R&mWIA6&_uY{DqeDkOK@%2_vI7ibl>$R-Q|t-=u5gh8NHSX1ob zZ91p^`0a>6o%RQ$Cqo6Qpk>-nPOXnuLHxL2AA)bf8YiVe5h%F;0000Ea5IfQowI9-hvuwR$tP^fy(>8sSO2|8{wRtGpvc@#B$n~B~Rwm&yIIB)&jy;7gW zTKL?7mzK@v|L<(N|7b3=;GHmT*|XKxR_ zisKEuaTo73N#D@a7GnOhx@e+huI&M-u%#?A#q8EMMfY92V!WoXj#HDtTEZ^x>C~Zf8IWQby>8Ib0dT5wN0yQ*dG`x>m;y#Wc*hW`8x0OY*zD)2SPUjd28<` z%OxHB?A^isVY&9DKSD{2WgAXtCo%nb*|kec?7;kW6+k(LjH+Fa;+@JJK3|^tKgTe~DWM4fm)lPg literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_18.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_18.png new file mode 100644 index 0000000000000000000000000000000000000000..dc0c995c1740abd4b151db9212217ae66b21ab31 GIT binary patch literal 240 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8Lpc25__kP61PR}HgT0z}*r?{-FX zWE<-}65ZUk;-*K}5&`ovw>5_iM|5jLU$D^Qq5+ n@{}|C|0&ddj4!Ln=eK1nP+Fp}pvLeu&7Fi*Ar*{oryGhn7>KakRjAFI zeaGnTe$ECiwr#hs{xfGjv8?z?;jcT}|7oo~?`0ESU=!|O6RPnsrtw1z;|C_z`+}vyh67C8_l`HcI9<`=B~UwS`K7s!-oD@Urg-ZAbw8V& zS!;YBZ|8X2xaix|$6vR)#_#!ZH88l2^=s@N#=!iAM+)aK9^+zlof9-a59mY&Pgg&e IbxsLQ0KN)U(*OVf literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_36.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..26b9172e8f92ec58982fc5db164bd8f39ac2e022 GIT binary patch literal 271 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawu6epRhEy=Vy|I0&lcRvk#aM;j z_oYR~D}9qDyCy1fvHzU#^^e{2L)ZUKf2Xx{%9e{4OnGzfbv{;^cX%>K-{cBDe=lS z7j`!@ab>Jp8S-k@dxlw2-zIlId+m5PO`1_^*RoAFmF$|$q+~k&m*tw>Jh;C4*^)9o z*H>CorA|B)56j9OY@xoJS#>ZbD-FbExJ^gPGtVbHE_*{=R^&XgdpX!*kL40>)i RWr03q@O1TaS?83{1OPOsZan}1 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_schedule_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_schedule_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..1749ea2758b23823affee62e5ea08d2e899023ec GIT binary patch literal 613 zcmV-r0-F7aP)_LiH=ABRtw z+}&?=ME>|WFoir0Q^{Q#Xy6Vp4w1toamO&qxK5O-lrmI$id2eeAdz|s@g#Yyrw*$c z)<`n=i&DA?(8dMQSjKev(wFHhBaI8RL7)(dU1f|IF@~$CZq`XO`tlf6!)US6h+0%F zDH4S;R132u4giR}P%Wsa=ZO(Cq6$PA0~7_Q`iQri3RE>-j{-buP$d!%H&9zdSpx!W zMO}?wF;y$6Jr3wg8!B9B$wOTbu?B>35tSSM*CAAzQ$QN(VEA8^sAWz8%TclLzwV-@ zI|a-@-3kAz0oB(jpf9SyA%Izy0EbINH~Scp{3Wv7^Ir)m@0ZxLJR6L z3+<1o=|xja;tak6jI_RJQ&4U6m4sN$LsUJvhEicEcA<+^N(%tHOvNrJ*HD8e7J9Mj z7+@&Zp@w6|NK?ZJwaht^B<9eHDzr5HTE@6H{ck(AI1FBMqX#ed(J_TWTJas_FWc~Y zf&ewq!!KKt9)1;nQS!<7evvemGlRbLWd_ShkfbDJ0k$zh`W6#jS(4WgG=%NPe&00000NkvXXu0mjfK&J?I literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_search_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_search_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..bfc3e39394246b221f7d4617aa5600a6406aa7c7 GIT binary patch literal 465 zcmV;?0WSWDP)D8CL_;(V?AVEarj0ldk$~bl6y3&Eqek6=6UA+aBGp8+4bCOt0yJyz3VGY| z^>9EE59hXLP{{L0Lqkciz%eblTs;71sDpKM$pE;wf;`qWNA#EmA z3}Zav^tfQ1X+{`jh7B(9+LToU=QvL+>I0VO;G8NRYdGH+S07Zk#aU4-eqf#$*8o)L zVD1%%1x$}ceS&42s$y`AxljOCm_x;&g;`eso0uELpo^JS0JE4E#URIwD1Z{?O)C5yhj~>DnwSj*u!U(V21l4n1#pdNCjP>$mkQ{TM zA}DjpU_DNl!r50btZ+|1chvL?-kyr0${{zr@Wwl@G-*)PA2jglN`V8sx>8^tZ&xX> zhqt2?sN-!b1?qU2QeYP^Qwr?hWJ-f=e#?{&8JUKL{zpFn4bJ?-H56sJ00000NkvXX Hu0mjfDd@)s literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_send_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_send_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..ef59e77678dbd3f5d866bca9058b6e90cb8d6098 GIT binary patch literal 344 zcmV-e0jK_nP)&W`22C;JryNwK41(MIA#GvFb#~s zwsao25E&6n03w(GL@)`A!D$_85` z%9!`-s3_@X0OI`y_5>OaJWhc7Ux1pxX-=Z&t1o;=Bq}NC$3*rSV}~5rah@Eqct#)^ z#sARKe>b^SMWD8;A|0im5z9_QQGnQ=9+)gN{ZC&+5rBvy01-u99ZM?OT$kUFh@ye? qUBLr0?$ZKzW0Q{J0Y5k327Cd{Pq+sr^Mm~W0000P*@Q~2t!X1e=k3L|$sH+Y~FDHYabh zPQ@}s6FOyFA#60GQ>OGqgx!AVgl~4nA5QuuZ;9ivLP_4P#%dnR)5EBz&$PUJ)Eob^ z%XfKLFc@odLL#fg(P+$=tS-m;Jd(w|XvPMgwClZMG-rpe+VRCew8k-sv}z7V>s*o6 z#Yo3}Y21ml^!lJxZxtgwgBG-6-u7sZBWjwdIvDM9Ni(C7jl0%!E3#7bP9v`sB0B@h z)-q>nl(K*gJ6J1@a Z{RW}ye!)7Ir*Z%Q002ovPDHLkV1kE(!><4U literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_swap_calls_white_36.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_swap_calls_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..698cd5d756f3b6031fcb2ca274e09a781a0cf0cc GIT binary patch literal 484 zcmV4n)6YrtTShqzf{<)Td(u*h+gRXi5qIeG?wl|>6-E@o>U=orE8J^Cn-!M#g zKMrKo?|HXp@nbNHb4=0yR1`%~#6H)Qys>IGq2!7^l6ybfCAEZipZHBfzlJ9YCkN0Z zFXtO`HZ|ki$=$q^*a-_9IQQ%0JjNgDKvZVPTWVyE3Pw=C)Q zs5zRXIQukMfA~zocEBrEL!mi}q(IkLi+>#3AvM-ma}-H|O01i~6L(lInxjYx^oDgb zc;W=B(i}xnpcU56;E7$VT5}Xhfv~oBCO`oSP=Epypa2CZKmiKS7C@P|h5Va|1m)kS zCRoR$ft_MiUQqsxv&6b34eTE4*$c|QlV4#iIUx1+g&OP93(9}B*rUOE<*>(@V67SX zLHX}GPjp*y#|gXbPPwP1+XKlD%76JPnBnQ24;i4Wx50BfeI;dp@?KB5K=qxZm-oIr zyfdb3>fOGM0{LIy^+r6>&~MEHA4$Gt{EtGcV9W~@b-RjZF2xUBfVR8<1t>rP3Q&Lo a6rjI*j-$H&Y}$?h0000EAW}mHTE)u3sm+bV`tyCX^_WIr?G0ZNq*W z#($q!ew-FoxWr-!V`9hE#%$aLG~ zP`vnqRQ1-m0s%9w)*RU{A#{?xp}o|_GEsr~aAmXo><(4g4fAXKSWX-(`y;6>`JwUN zks>9x+;!+8z|LtY{@={1|O!Gg&#McWnxU?oc-gP_O*cNE=-I;oKqMX w;x=?e38`@?+^kE#z1W@~UM^uoBy({nhh5FflNAy85}Sb4q9e06s(KSO5S3 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..5d540589b4a4f9e22a8c4f1f292e12ec75ad443b GIT binary patch literal 296 zcmV+@0oVSCP)KoGGG(20u# z;3d`r9)bgK5t u`p~bKR5^nH` zG4KtM0O-ddnU zQb`a;`lt&^Ae9D1lgfi4NgALik`5?>qy-X_^gu$ACP+lm1r15pha_##QIb9g=&=Zs zYJf&bbwDGeTA(1Q9wXg%|8kB;^jz_DD}oI#1H0 zJ<`KJ(z-f`2=~7q7H_yP03yO2dP5u{A}sN0h~s&lXS;6})w52>;+iV}0000|k0wldT1B8K8iKmNWh{y5d1PRu~2?kC7U;UT= zr_N^cXMNj}ZsyAiX8k|Xl(j>y|G(%AHdBGz0OmV03NZkP61P*9^Is4S8Gw;|*rq z@i^Z5O~`&LSF^H2(&3uW+b>MJ-#(mEy!`0wC)efFl5M{lznoI4x{+;s;upRj$rU~^>bP0l+XkKQP@0n literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_36.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..44c28e2f2830f927973beaa3a143ddfe439f20ed GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawHhQ`^hEy=Vyh zQBv~(_A|Uaeg>M$g-&EJ3;(E>F0WfsuqEq@i4qW8@}AzdO6rx>m9XRe^SrNqJ^A{6 z_JW14-f=$P%=XJsxKGL9nM=c&PKKGnj7I8ADSj*`=EzL26jUe%O0+bb;bi0#P;hAY zVbJ!!)MT zJ4*vW6on^MHu0InUI})J{wu{0Z51sf8qgmi1S~}2>u*E?b|Ntkt<6KS2%km9OE%eA zM@?Zdr@DLQoICG3tCWL-gTp@q3+!-910SDfuE>%8){|kI8|wJ@)VU^4CR~{0lpdpK zbA)G1p5%n?n5RRL#He(c2TZtUDKveQr%E;`eIW`B7DLiUds@;3$)S-n*ky${aaP%* zDSRckP*$F*UMNn4I%6u3W}1?;9R^zLJja7m&=qNHY$0MIe`9{=u}E~KG2FwVeYIwWkp_xO{PPov%G4>rf@sfo-IX& zj{YcxUYc{cXmdkly=UcVlTu1il&f80W@IGi-b1wywEG;IDX5bYeJ2Z<)VEmCH!Le-j-_WLDcxFkHqfCwduM+pEQD%#j`+ah7 daB!G3J^?=jcHqf_AhTi@4yRcar~!F_Z<7Mh`HA2;K{RMA5wQmyDh$WiR0;JO`VwyoGd;H2~3Q_ z95WmaurR3!WH6L(+t1vn#$fzAztN4CAAWGnyI>&u^t&_&muZx=EOU^8g2XS&BDbV*Eo%j9;TGZ{Qx L{an^LB{Ts5$0AAa literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_grey600_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..a45093ff79e1ff08764467cd9cce9c1873499255 GIT binary patch literal 459 zcmV;+0W|)JP)^Rg6bi02EOMy8I7PP>E5&cw`H};>JLO5x(H0*m!gcfO0&g+YoU~OT$Z}bRkmf?sBOJb(@Yy;OPd^&K9O!Gqx=pfHwdD002ovPDHLkV1m+= B%1QtL literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_24.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..2ed00343b8061decdc32bb522bf935b199bd4b51 GIT binary patch literal 455 zcmV;&0XY7NP)Vh4S+i9bn60&2*5;>f*zm< zHbA08N&`>?3sB(`39cFX6F|yiDU+1=u$HPL!nZt*K26j57QOxew>+*#A7|o~`~hxx zI`~P>#Vxq5Z+SZA^wTnK%l%*YmPechIV*2Q_SA+8@GFma&}PBPJv4s(JHT(k&TW&G zd4|YjjB5eh=e;!AjwS$BMA)QH7w{%Z(kSo20il*?B+L?( zMVSxtBQJ}xXOt67z?Jpss?oOf0Iy_Zo|TL-t;6nxyp>xveogDRt} literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_36.png b/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..2e751a40f53b82208e70aaa474d4395a81910a12 GIT binary patch literal 654 zcmV;90&)F`P)_7O&ty4On2@XE3V9dzP8Jcq(p`*@*6|CyVZUeYC9;eb zA>``#g5Qc*fu2;h#B;V4-S|F6)h@MgH|yvD-!%2rmRDRQ3kKsD;oImHj%x0}G)R>vLm+2n`D%IHY!LVa`UVo*UbQ@Y6=< zYHq9>p;a}ZKk<_RaB#(+x@oiQ*R8nhpIQh#R@rYLOj-yHs_f4Y&W9J8R)_0G+6cQt z3$@v+a$i9B9{&0<=H#A1mH)8T6bzp1I>>IT!Mw z=!;z}Av9TI`;^|o99c$eiw!-ho;GD$j@imfvMkVNS+E+QNuHB-CB06@StQRjyQ1eY z-l4f~Qx@)}?va6eBsPWf7A}8DtJGRpV5myXmnpVYr#Lm;e9(07*qoM6N<$f`lO}%>V!Z literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_back_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_back_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..32a6d91ce8618ff42524d9e075451a13b2945f87 GIT binary patch literal 191 zcmV;w06_nVP)ujk_S|`RRObEa2eyW4o|9^x ZF-)JT^`XP~>K>qh44$rjF6*2UngE3dEv^6n literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_backspace_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_backspace_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..f6a90accffbb4b543e8f8022630636650d0f6c73 GIT binary patch literal 543 zcmV+)0^t3LP)Dr}kqH)-CQ&bGvjJoL*2Yo@dQ~=lX0wpiQer^#GSsA8o$3+RLS$f`cLsAf z#r)qJ_`y@0*^Oz_rcIkRcwFWgr?gz$esRhRHV7iHyUGX3>?=1jpm&tp7aHR{q3oXb zbFOnv*?sBPAldsht%W%m^BsByX2;);Fhh&iWdThJqdpl}7z^Pu|-S<8-)gkzvh&y^=R$3bt93p5r73dA2;qK297oBHOJlC;9B| zIcQ9_B~6#(BsN$&Xk4}&Y2T8W_ zAjwu9B-zS?s>-$sqN;2sK~$CPAh3H$xqYT_&=ro0ac&TS-zA>%k)K@LR-AA^LpZ4D hO`r)hfhJH5_Zt)xGl39wZMOgb002ovPDHLkV1j7D^}qlC literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_block_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_block_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..fddfa54b85576986db9096ff67fc768ee70b2bd3 GIT binary patch literal 973 zcmV;;12X)HP)0!w1IO{x1Sd{%lZ9j&aV5mHi^d0NLky-yTnWv>H(|zy7L>dI5tIaL^KYS`#wPHu zxNwMzh{CAB5Q=o|B8Gqu5r=DV=gbwq-Sx-KkqtwZWL1pbmaxYj2rjoKgDOMUFNC_A<oFWK{G)G{${gRjFZP$EKiYjHhWGXYfw*JPL)dy{^SK*CaO#7&Jxr? znYb71$7I++R)~8iMvaH$+Vq3V6&ea4LU{KG;Nu477+QNk)S<%MBslI$2qV; zpMB8(5xDF0>Bt|pK}QjILEtQBo|gy=*#$jAs_b``QzFM9BIJop&@cj*oaPt|R{$B@ zKIlI3icZHlhJbfSX}h34J|jh!Isfhq5>ZGGI*(MyJIv8K`G6GDgBFo%j&rmrql0TgFW|TnDZ6yk?)g(I;kN8 zj&robwtqhiPmxK-IodQ*#-s(ELqhUia=HkS@${fRBBbarNBa?}(VHG*m`BzLoaY3r zBlj@d1q~r^*-?&m6@hP)gS15?;-J%Na$IL?Zo=^P6xg0;{<29!+W+i$qqLccw=nPtdNr~uQ>ad zCA%-&qTv1#c!(!tQD)HJHTfVVB5c*Trw^#>Agw@=$5cu4i8A9l;QoTNJjb}mO_o@t vLX|2NR$1Z(7Z_nDCff{t*9vL{wSxWu*KBixf&sj+00000NkvXXu0mjffyKys literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..99f57c12a8ad3786645f6d69a9e935e8d5eeb3e3 GIT binary patch literal 794 zcmV+#1LgdQP)N|3DEx&_YneLIg_-!|8m+B48)l+u9fv-phBeh_SI& zv5SdzS{P77VlX3waA5Yn6TM+qrr15z&b_nw@!rg4v&ovHIhrHQ17SUPkyV|oP7EX^ z1|lgP5J~BPNJYhYluK0=7*M5*D zSx|u~#ffqYfjQy?3DP)n11d0C>Y9i-%x?T-&xju+Nzu9Gj9U&f%C2{A5J}_a2gaX< z=Ga_DVD@=If~3Q*ltF=q(fJ;%vG<||RY5WwuC8Oz*n4*0)1XR7=6>G0vG<0e(Z}p> zdq6hDUr3!Yhj*qY(fBZDypf;^NR~6h+S{mdo#S5wr~*>E8;4nrYUerr%K>tbET<2% zQT=yRJ%PY%|39F9ywo6^tjSzM)5e+?+f*w~ugB=#|%-VAr#5^{sI1BdjG&3({V!vgeWj`8fvEjWpAh)M9-Z zeFEg=7?62hlBAvZ%<2PV0_5db5NFJmX3UnBZO-kmiUAFBa|GxxK9=U(W-TW1mT2SW zDA1th7}5_M&>$yAfCNX7P9gJvo@duHfXGP$L{1tYa#8{fBTEBBP8uL`(g2Z@1jvyF)PNe$ YALLl~9CdCzDgXcg07*qoM6N<$f+&G!-v9sr literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..6842da6d0af5e839692fdae3e1ab70ae5c1de281 GIT binary patch literal 1080 zcmV-81jqY{P)p7U7ahha18_&be8{yIe*YvYpu1!H$3rkf3R9{ur3AY`dziPIm#D%p3gB3OfHMY>MHILxiWCj1eWgJQBij2FQC66meNaKv zrm#;C*HQfgZHux+pff7fG9p?AeG%CQ(Vf#KE_!$$Il~;X=h@wR-q-gBcP{t7&Zxm= z6bvu}%?sO#&nTmy!NoJPE|!US3ji&<05O7v!MwfSHI zErjW;s7o~NvKz*WWLgT=ptHgrppnn5FoAXpT(>c+v%+3WV=Gu`gbB0^T$QR>>yk%b z()j&;7}NApSY3FFy2SD8G{dL?W~Y^67BT?a5@+_&98at;rkPpY$ifHWH8jh6GmL3Q zR!{y3ok*VlNHaA!VcZRvwXrIBY7Wa1iDxuds~yHPA1kk>MCKmNw$}i&&`RM>NiVU0 z_C)F`WqSNDou;t*h!rh*gfatum`oE`2NNt{IFURoyu3JJ0bzer;ivnRYtdo$sVM z#@#Sx`Dw3{$46;~E+b4}W#IZ9Q!EIy-|M)BD zH2TYPl;7xsNvs%_)5_J;aFMc)5*ca}OMulvJ4VSp2AII|eI24VT)~NXsTpO>ZkF-| zmLEvhxkXnoC~T7w%*GO6y9HL%LjZuM+K0!)5?}&Lpk-*)U^bQjYnNGZ?@*HlmH;!b z|`MT0000Ksbir@OQBE-g|t&k+Ykz+ zv_rwEC`K3YWfDSS5J7RvWL_XcKqYFppN>MvIXStxmwO?<=lKUdap+5>QmIrbl}e>j zGRKXZG-J-9Wt+BCRc+a{Y|)qQxnSHenb_~4{1ro{d|_SL)_iW#>#}--+KstyO|7k% z^}hD{fL?Las(SQ?8(uyLC^P13^={64vi*ZH6XrFlAAKO(59m$bE9xH$9-8v0VFP+~ zsHo`BYrtDhy5x~1|0(JlL*+odW>xLpwjW$JqEnQ(%e$_bmsizYJ$r#Zu_nI}QN!c% zTk&B&=mn1z_eM>icNF(P_imuq{7zFq{AzF~=!Cy%8i+rA{68pj1)2(ii!u?~%+L}b zZmWdrvtU;=W`?d^6guO|>85IXU^O5DfI3g62s-|^{I^FF~F-L?V(yCEW=O=9B zb417|EjTI~@JoKlw1WKR;N}vQvpae>w!v}f>M-hs<`NyOS00000NkvXXu0mjfwpIZY literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_36.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..13ffc2ad75f087cc182d8794770507a7fcfd0a65 GIT binary patch literal 778 zcmeAS@N?(olHy`uVBq!ia0vp^IUvlz0wh)Q=esd5FkSR?aSW+oe0%k7_O({|V;|4I zP3t=(Qxj%zNne{$wg1(U<`*xk?d?BQ#@8Qw{i18xwA4rp^ed-qw&3qx$?_9Z zG~0WmH{b72oc*=aP4`N%>g=AXOKU2u*c5 zYTtaiB<$NdS+B3HQ{Q}CSe9|GBWQ2JVY{GMZ#%Q}Ydy-#Y`_0rCTo~{jdT8v6}!al z1X{llJ022rb9$QZj`L= zEYg4MPu#m~;o^iTwyU4tPq2Q~ou4ov|=G;m>&~!Kyv3;Rh|Ud@Ve#AC%ypU#|LQbHF>V8%sYphaZ}DSUQ%o z+VswYMYp8ZSidRTT6(ZlF=zXlU;C~`m){W8Te0tbj^IMGTdBKUnay4m>FNk(Ev(I5 zo^he<$EvDn99J(*v&mYU@!* zw!JF?1gb2cWjS0r#xWU2M~pd$6azGUBzpzYc%)-{+lA lH(r`}FS_iU<@100tn1~RCf(bA`VP?l44$rjF6*2Ung9xBz!Lxf literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_missed_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_missed_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..2374dc5a1158455c8a7ccfc02d821e2144e9952b GIT binary patch literal 291 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawUU|AWhEy=VJ-5-T#ZaL2;{GoF z<#sD0*1S6%*_)u1C}!y+IN|qQy~GDGnoFkyd1)@KkIxi;xANZWpBMALuh4uR7aBji zL~e`aSLZ5Awk(U;U#d8+6qMz&JMumcJMH+_kk^7CNvME*9@MnelF{r5}E*E!EJp2 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_received_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_received_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..58421114fd7acefd4713ed01e079a58747d96a7e GIT binary patch literal 257 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawPI$UFhGg7(d)=3>$v~hjF|5Mk zPn*U9r~Uo04yq z@5#!^dNVD~uiI(S-COYBKqK>W|M~h}2Q0a`enh%EC}tn$=ZZQN7jWa;r$#38UF;%N z@7^>w^&hki__6X1J7=2GwHvkD9-$96#NDAf@tr zjU%UpsK@!04pn~aOR8?DJT`H-lzyL|k%^@P2s|z_H_WiQDQejD0_Z0OPgg&ebxsLQ E015VIaR2}S literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_18.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_18.png new file mode 100644 index 0000000000000000000000000000000000000000..6f4dcea1f3cdf34726c7e881e97a8b40d985ce69 GIT binary patch literal 491 zcmV$7cnH?xJT@P zd}EMr)YT};H*OPKB`3e=<1?`t`Nkx%8kgi7&xw6uSbkBUN^FgO`9+x>Vk`8?FQ!SX z&@U?jrntj6htwS^B-R+#9^?tB`_5bLGsQR;I7LD2BEw@68(h{u$P;20F|T%!}I@sJ@xS~2PjWvVoaXw9fo4DgKh7kmf&RIqP)a~F^ihkCNXidBsWB>X=;U*@F%!%#fVZaU}txjgmm7*kE>_wfD zJ4vghX)Y+W+A>RYW}(s9ms0kgvz_-nXXic7bMt;aQYw{7rQ+a|A;-#I(=OY{5am0Y zWfwW3^~f&rM7t`x_(`-r*+q_ML$ZrWqCJ#dj1g^AcJY*GIgD&#kT@-}i3`LzE}J+^ zoB`QH3vni76Nb;kX_ZZk5a)z!;v#YO$R>6Z?LI~}VVI$`08h4Yi&6qS*+(ZU3-IIu z>zHA=08g&aOR)e??y#Lg0iN9A2}>4ekZW`hc1f;bc*&AEHpw*(5q4XyVR%khr(9zf zd6rDFUaoP2usayJMLpAmosw%DC2WCxa*ZLvKCxA9QO8@t-q9$x*vU7-#@QgZ=w^|y zaT*l^!(L9ZMYTZ>h2FDG5%3w|pEvY#jAo3IgrT28vm8(f_+%;eg;zXakY28EhGta@ z!!U(@aT=p#@W~Qqp8cv8YZ#{3JsMO1pDg7VQ}r-hr`Qx-`VXHhbwLu%tSQXU{ z2YEroR7)7z38;u_k5;bnkuu2+*3!Wc)5OWiCJb$y=Ml4%G9VW)G||O5GCXFK4}9eZ jd2$TkDV0j4QgQwO?=x#gyQpL<00000NkvXXu0mjf@K6c} literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..c8e69dcebb98d43695027fcc7e39a339c84dda51 GIT binary patch literal 666 zcmV;L0%iS)P)y zDuP#FBS9M!QcYr?x(Xj5^OKhEOrZ0;%Xt?M^PS1$oUvkJVg?bG2*VOq|FP&lUkJx< zKARBwK%20%c&{z=j$iacgSVPOZ>ZBRKY6Vs^pYxn!v)X(MaU+{KDTId#}NxSK|*6x zFv$sHenK`COmmFwEtDe)3f@BdM8ToA&@EBW@D_@SSjd>rJ=jul4hPAn$ZYd zQ(^?GM-r@1H!ZY@i{+CPWphGpzG8()mbM9@HXpGBsG>9Ms~`YLf6Qp{EBmWamEC4dDr!XN=Tg=UR*LRnyXqu_l$^Po#V$T zj`&?_>IiL%W{Dt*qP?plloe0b6+u)P>h$wELg`L#hA>QZ`WYP|H+WzkLrdxi*`3}7 zVOSR<9(Dx^Vxd?l7V1BL0REY1s|}3R@&Et;07*qoM6N<$f_%9k Avj6}9 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_48.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..a4e7aea72dad80db6724ac6e961b8d942a7dd03e GIT binary patch literal 1309 zcmV+&1>*XNP)ymi__c6RKd0kD>_QiUlGZMZ=)w=Gn?ehs zg_zW6b*H9Qt#(^*zu>{K;JMl%+lgTFf8JHNW$LuYsC*KqL5tW*-C1=O-G)Firji`kqGet#5%& z(P+N@e*<-Lf)Som!FOgD;~rnp=`K)?Ys?ZFvs@$RBG7)O2$d51lLqQ1bo!G7+D{tT z7dKFjDbhfRY`j1}k`@Nz1nOj#v@lDq{y-;46JOLHXoNIzxBfuSNfV>>2da=Js`Up- z85&3fX&?=xfizGIO5Elod3xxel?)kL>7a)^C%MB^ngfkg34LkskZ^@u|^ zQ4A^21gj9ou4W>XK(E~7F(jG{A<%T>i)#^`biK2aMMxw!QuaPjgj@569Ab!P{Ks3K zF~~vMkoS1R_dtV4O?$XO6&qEC=|*aL-RD4~HQ#%(+#(9sS&mq3Vcg$9wceWZOc9kL zyAiAVd<}FDvDm}~>g6m=h{cC~23l*)^8<0XWKFcr$3XWHix-H?8N}iv{{n46jDAKE zb|FT$`xa>2G7if!MG_`yw~W*#{0ejqF?x%n4B0PSp91w-UJG6DiTOtDQ=pP%6n_I3 zTty5v^V*+4w-JL&sp5h%OAv!2{scOS7(9e43W&ke{shV+28VFP6~th{pFll`!DqPQ zDPnMqKY==o%14h$}851`qiDsc{fjgC7{&zy{*ODL4>8z{ z3%U@4>%pf$=jZH);sM0yMc;<@3lM|LDUyVjEJF+~U@KyD4@uaG7~KKB1$u~B zJWE_oAr^o0FA(%1Mw_@q9KK^7Vsr!e80Z0FO>~BOIc3c=kH>xng1v~{m+VBW z7Qoj)W3(Vv+ZiGX11v+Vwld*wAQ(n!x{5){*qCO3E~KV6!RJ757$pWf=M`_;KpIE`X&?=xY9I}yfi#c?(m)zW1F8Q4L4egV T4fF-=00000NkvXXu0mjfM-)<9 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_black_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_black_24.png new file mode 100644 index 0000000000000000000000000000000000000000..b26a2c05e3f261641734c91aef9322830ab10daf GIT binary patch literal 254 zcmVerIh-Q-qr4!cP|^dng9R*07*qoM6N<$ Eg0vTEBme*a literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_circle_googblue_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_circle_googblue_24.png new file mode 100644 index 0000000000000000000000000000000000000000..a8eb2a45ec34edcf07c54690bb34b57157bb8dec GIT binary patch literal 717 zcmV;;0y6!HP))(y!!CFg0Tn|$O2g)3-lKY)Px?4;09K34_he6 zmOfk2cSdwfv#xPMI-8z5~TD2dC5=VqbwS;0~N}cW`m;KrthZ??~~v0!1(f z7nnIj=Lj?g7pU>61NFfLu79dPZP*16;KzTQC$&!zXcj=6FYpvb;3`a|10?~)X^?Ah z6%xrnd0=r4-c?`V$^_~L8t34B#jzcUKv}49NLq1xc5I+aDC-!9l+ZdR&{d7&91M;L zl-D^9$+>}^z`o9LNC8bwpkAnP7r7(etYv^ZqK3A6(D04cnL@4|7O zoiYwtasu5yFiwL|q%h);H7C%P5$E6qMN%J!Y&d}mW*mMb4{=E0ArLFlS9Tl^fwtg; zB7M^uhiv$Nq~#;2ibK}?fAeyYo>L@MamZ5sL{TD=f;eO%eyJf4Nktqo6u(#%h@>J8 z>51R&5QwBDP616{H_TGaaY*j_mTRgt4jE{;X`d>MQ$kD2W1m!09Fl2!aF{BJBlF;p zETkhTh_lcYm%Pqtj z)}h7<<9rldhZ4|Na-Ot<*P2%{ryk=>HLqmaQZGa23~S+?y1ZCmAoyZ|x6rElt0{&s zfhDYA0|nX8XG{9dP}{31^s_(~$O2g)3uOKPvcAebNsTgt00000NkvXXu0mjfo?kEX literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_close_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_close_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..6b717e0dda8649aa3b5f1d6851ba0dd20cc4ea66 GIT binary patch literal 347 zcmV-h0i^zkP)vMkH8EXyh{JTRaptiwcq@D(P;=ehLbl?EMKm*m7(@7_siS}}k zNFtnck{HL4mc!ypcyUoqJV~4rM^fS3C#iAnkyJU3biCmDy`VZLOv=LXld^HVqnhEy=Vz3G_M;vnGmFmCHS z#YxI$T_5;X8ao?Jn$7WO-DbXZL1B%D;`8Hcx|f;F&9j#>YVDl*D&$vu=l;@~-GMR= zH_vr4ioV+FaQUjk>!S|eT=_UvCOGIS>zBQHSvHTy9OE_x!;QT{)m0CXhyCqQpm`kwwTuq46Dm*Z(Mkrg@GFZgNRA zIUME6ieR#cPtn%6__6GH&4f1#T%6B0pM9!%Uc~4mUzeAH^M31TyN)>=ta%IcB!j1` KpUXO@geCw37i~lU literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_delete_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_delete_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..603f28cbd1829c04d5efd2720d58e7c72ab72b94 GIT binary patch literal 177 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawDm+~rLn;{Gp0i{;Y#_pVFkd9k z*H0mt?~#JUD>IIw{dcT6mZ^9O=J1@8%*lWA#QW#D&0Z7IPfS=Sui(TZX_NwF+4F*F zMdvoCfajq#B37JxgECaMcqJx24{Y~Js@jWjzc;0qEGLy*t10@deX)~w)zs5wFSq!pn`O+meKDh? zYMHQf$$2>wmAMmN{<-Kl|7J6v=kjE$jgGV5IF??@oZJP*~@3M$%Z`7U+NVtYie`5P-Z!gp_9~-BOI9%gp`*!`t{^yCcW_% zejFinp-cM8RJCKvOn~w#M}hJpK>6;Ag*tBC7n8O~=t3yjb!w*yS4}E8>}&H~aMiPR?~iKzuSyse zXp}4{<_&%A^E-8&QV_H4OZ9#$y=>8mw=VTQGYnea6Y8^ib*GqNn0dXZ=Ey%uoKl_V~M^ z@W73UuQzIyi;CX9TK#xsc<%FckFrW1Z|wdP`e(gGT*a#}>7T22MENh?xqRK$$YWWO zJC$w!SeaZ-j9i`ic)oabdqL0qmcuVV<&-^gM^fk|p zhABSlxe8)#>#77QJuA8TY`rUxw`wPlcTRTo+M**_4W^H!H?C$g+ZoWd8yGtbp00i_ I>zopr0D~*a_y7O^ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_edit_grey600_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_edit_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..f1f9ffce89e69b760ea6b8be14ddf522260aeb3c GIT binary patch literal 305 zcmV-10nYx3P)0%-Dc@XJIh7yCzUd@y?44v<;XkMdJU#YE}S&UjnhsVol|shnxwTir$O@P z*pbwn4{3qK0T^X+$oU)2nVf+*CvwOkN6D$l8HiJnLk=h>1TanrV4NR7mC>Um7)J?; zhEKX+90e#EKX`+2dO*?RI{=H*0g6sPreGY#7@K-;1uMqVf|RAh00000NkvXXu0mjf Di#2~T literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_forward_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_forward_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..7bd5b1635b409f847c9f6de56ebcd92dd767c889 GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xb3?wz0qptudo&cW^S0Mc#1}qL(uK@CyOM?7@ z85$T4evO$5IM{I`Q17{UO^%HeUaAwddnQ|Gs;9 z+hbywm1?g@=F;Fx9uvPgKMw;^$RgTZCP9w31C~tWy49xC8?r7}bP0l+XkKgGeJs literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_white_48.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..a0a1b4d4f3c5213f8803300e4428968bc037098f GIT binary patch literal 123 zcmeAS@N?(olHy`uVBq!ia0vp^6F`^|NHCnYy)O!+m`Z~Df*BafCZDwc@=QEk978G? zlNF?UngS2}`TzevKM&6zhgSzSh&FAUu~N}Q%S7jZ#sXI(Nl_`mr&>D`M0%JQOutw- TbRR8?0GaCP>gTe~DWM4f)Gs9S literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_grade_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_grade_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..aa5879215e9206b90f3376a23652b31993078993 GIT binary patch literal 676 zcmV;V0$crwP)LTbNM2H{@gF-3{^57w~4t7fl zN(f8BB*PBfBrHmVEG1B)%ycS#Lrk2y&F$I$*|T7uj}#Xd_g^5Ne8mzT(5BeIR=iA; zp;*Bc7St&=kjz&W43n%_z)6;rDi-jXC9mW>a`ClKPNNlHcjYX$@CRR$Y?hO_z-qN} z4v7r0+Gi5w6prCfk(@#o{&dP2?7_czcFGAf6G)Sy4>uD8@{=@08|Mk8TG2%U9|`8Y zq6rsetmg!&GL2+1@lZeoH8jx5Q{FPj1fiN>kUpN!LIX8aP=JR_k`yWmsiK}{+Ua3{ zaptkZJYx*dLp#mXQ$?WyA&(KFZG=1p#t!<4rhc|7INWp*EiZ6ueWY-oXlNl>q2e<3 zn&*Lg%top@Kna6%cvEm!KvIo6b(JgzhfoZImBt>@MAXeqe4qU{lTG@dP zta>c-NMIbRzRNsvh(xwbqmoFRlWDXOiF-1QL4uiLieNs-EVdC$2U%p%K``kui82Bi zqFDb>%n*Sbmq|3?&otL?$pLgo!kj-<}>XSL7F~>?@C{YlUGR#U| zTr!0Me9dr!jamn3++qe_M`Q|DS@x3M3K2PUv#d_0(8Z!}lq*bBFv_B5GJ_;0fLU&{ zNfzMd4s*Z{5@iAhfFAZL0(j^JJTie(oKeI`;4CGIi;Ihk3)f#EI?}L6ho$}i0000< KMNUMnLSTYk8z!;< literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_group_white_36.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_group_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..952e15fa692245f88201fe3a2bade7b2ff4bffa8 GIT binary patch literal 581 zcmV-L0=oT)P)JO zNu`!mp*yRnRdhtyMJD@0b@ppIy1Ny|s?2vw)6ui zCQ{5M&U2N=d?H4SPdw%-=h;Lt6SJ&sq(Fubh%E`5I3WFpVz;8t-0lhd+JNeMYIeG;N z*rMnppoDxX2@)`rT0y5P){t*&f&@H}bUHAWO7g8T@%3k;q|qqEHufLmx?}0})Xj$^UU;J~5w|Ps}Ig6B98rGcz+YGcz+YGc&V4ee2Qi T17?BI00000NkvXXu0mjf{~`sn literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_hd_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_hd_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..dd08bbbecc5141dffea4d9f61f99ec24733e55bd GIT binary patch literal 290 zcmV+-0p0$IP)0tqBg!2}XW zpv=ccj>hbHBfkqBdmW%-U2ULiZ6NzkP|NtYHXh_Vc><8*LBxVG6G))=Z<&4=GjoFU zavf>{T^ZQV`kz`LfdmprAc3~pt`^>iYVv`eiR$J9-SI_4?==1^&d&hOJ>~@&iGi7w o60J0)+jEP)?!yjvXH^7kP5;xp(p0|NK1snsaY1p(b4a&4p!#I_vDvqRq)^ZCbqK zDfhU9#Uv}qkY$bye&YVo51uoN%^p-_g=3tuBbF&-30mYUZos~9I~!1iU0lMp8TSpU z(Z!{x!!3Ux%VS(jJ+@e5feFeKPAfCPbsn%y4;RxTtPju#n=#AZvcxEc_|9>McQI29 zM$&?845vvIqiCM@F(jJ~6g{lptTKdAHcXvA(Su6^s^MgOWC}B2(|p3oxS14Gi9A`a zC}9#b#v7dI7vsr5yAjSAOv28xANgKN09uS3Rtb}$vB<&I1_c%QCU0e?Fe$qzZ*M+R z7!0(66Rl!AbRQ?WI|#_iH#$v*ynu%JAhsT2^`JSNsEYB_HJs?O9<(7}5*Uv)#pY*P zkfklgmb`+N#pdr=9cV_r(HZp$D$y6)r*)vZ7}>&jZbv@7I?%cpS@RBhD7HV*f#lz? z;2m^Be*QX8ON>l-2VD@`k98pVjFr8E&dXnKI?#z2DR>7J#rD1qpcJUCj+t)qxEAxq$XCTF@lj%t0M0 zdXQn3Zl<6PS1<~YXp+~Nf%d2*`)|-ZFF2&<4b>0Cc1*CP`b2Kdy}A0=pj%ntL7lst1b~rDWTxjTGDJwFC|(e zL5RJIuuHS{AcCGPYbgPhRj8I`?J1k8acwr6ulF}IZTjZTychg`fA^XB9Ov*?(q>MQ z7@)uiW0aYoLWK#+j4?ui0aTJxB(nlXnWagWsJb+n;T@jdEUB(P#tQFQzRSlgd*=#XPF1}8JV%Ke%rmj-Mr-w@pj7a2l5)k^3`vA{2c^@VL%iLh>KEW5NeVI8&!+s-1v zme`F-aC_(w?02@=gPkGRI)_jRZMd)pi~ zi(U=oX!GcOY7T3nH|`8}488A7VFPs0D>{SiMQ?>i%wPrddSso!a;%{@WCj~SuZ42B zU(tKT3^s;d!zt`5^xiOomC>7X3cHNnyJoNn^roG{K0)t<8LWcdlv7w0y${S_r_np@ z6c+kD0uz|P1ST+n2`oHwy!pEXCNO~sOke^Nn7{-kFo6k7U;-1Ezy$Vxft~UmcFGKP z+d+~Re>&{_KMw7X!eVMa- zN1J=8!tT-LTPAtQ{HoUT2~1$lCNO~sOke^Nn7{-kFo6k7VE+N8m}BGF%+4JE0000< KMNUMnLSTZt^|@#O literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_history_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_history_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..1358a129cf1877b517c7c58bbf225e8b1d75cf75 GIT binary patch literal 870 zcmV-s1DX7ZP)Td!M-)H8VR$Gkd1qU+gtLP*j;rCX*q@ zA>7LcbYT(;Sj}n{Fp18*&pjMW?ypTbflrxFHS_p{k-<1X@YM1gx*LDK7CTRCYI z`^ystGKQo}(jW9C*m|(3Qebm>VQWo!3DA{fPP0;?h2GdYrMs1Fqu5jd*qkxguJnJi zW@0R3e+A+oR$xq{UOu=T+g+-HKRl957LJ5n-aJUV~z~xq(|kAZTN!q04!%0B`^@)?VRw zk%4TTa(0qAi`gwk4!~p%OR;yxk#u3K9Dr3kNqlF^n_ifHN6F5`3&s zqbsX1VlI}!6)Yjd zVlGr%>`oWbYR_(pj~v%99bZ$qOn)94xswUF8pln4!J9>nlWYFPIfoB9nwq8m|@f&vEk zXhJXy z)&q8Jdy{=h?m>-(r*@dK*d3epCi{|HgU+qz4*BYtIwp6bB0wo2#+nm8I>3B8iEGdk zTNzJQxB%cRn_*v)JJ1{dbN|paSFGhz>`QV3I>zMAKdKnfM6N&`Di|k|EDy3@h4PVK zk{o2e3gsieq-8-3jN^&)U)Wy&nw9O-LW-|?GEfU&#WGOH2p`=L$UkuoJ#eZRDaa7g sq|daVQ|=KHU?d>_qaXz-NI@l=ck_!~>**H-(*OVf07*qoM6N<$f*#evGXMYp literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_info_outline_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_info_outline_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..c41a5fcffa8c4dc3684252fbfd61623837e19d50 GIT binary patch literal 953 zcmV;q14jIbP)+=u1!Si^=c~o6pU56D8MW!jS z$u@O7JnC$-Nr`E0Z~~QViq1F4UDojk)8rj4KiUtv${KCrYEfp?UeGn(lf*h#%mwiZO?K>;SqC6p{w@`EooS#EOw+c}UBbluHuSO9kD3{Dexd zGgQ&NCewM)0=iXlsD$fh4c%;~LATKTP7f-@j@01>+c-g20r3E3BuF*`h>_@^ zHN+KB7e-Jm@Z>j$y%;(Bn$f*7_b_YN7RCYJVeH7P%ol+c!LiAkL*xA)X9%M!t}A%e=*t&auG}M zUL7k|gPtKKgM)4$K3fdZU#`Cd2c5t}oVOJe{qaNg4l!>nXc19Cg$22YJsc}RIU0!D zQ6KVKhxdR-j0Rnxtv}Fl zg03K-O24t7lYB&c=W=+E>@fn$hQ5wD$_oT6qv8ggqJe-vjQr`djDR|Y=pflR=t-%+ z(kr36+3A;_^XSU-C(b#^3v@H6PJ=SMLRaN%qMQqSME8wcL$0HkK4xj7 z`v)iS)q*bxcDYYB<~wVOFW}3`r@4H|@fyE97P!cfkP~%@MH=|M#7TQSm0^y9)p&}_ z7{lc0-Cv$z#&CH?jf4HhF*6r<<1|RC&P|h7oP+#Da^G2|VEz(#l(!^NVZ`1w`3S4D zh|A+Sm+k)}L4iBGp-Gr;RJbh%++L9EIM5D%liv*A40h bb%Xu~a~|hNXxfgr00000NkvXXu0mjfV)nVh literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_message_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_message_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..0a79824b8ffdb6ef7da089b69866c9ecdd395c19 GIT binary patch literal 269 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawu6VjQhEy=Vy>ig=Sb%`*!`)Ti z1iYs#Q1vNo3gp>8mBXoEq1^SzJsk=6cq-24K8WT~Hn)17amMDuv7388ACV2uu-|z9 z$f*-?JM5TD=Skjey~cib!o^(q5`VY;+6&r}xwRMAElVBevq^r5clfoq(UDEEWX}H! z;g%N~q>WA}G#eS6=)btYM1butgVY3|SXF5&27y4S5743 z&aVY_>Y^emgfs$F0~UBKaG2`QsMW|6%EY>gg)4*;EMfQJj%3ON$NQ?qVY#AVt#^R_ OWAJqKb6Mw<&;$S|Y-W1^ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_black_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_black_24.png new file mode 100644 index 0000000000000000000000000000000000000000..084bf3c9f4d780e5e79d6d64e9c352f02f82b207 GIT binary patch literal 671 zcmV;Q0$}}#P)RCIN6P=Z0J1;I^3 z97|h7&_NMn7XK7l6;WH7qNk|?cD=RDI<>;eAjRtkz zafkhQZ7Y)~_1(&3T5i}1jNgq(g!6hk=nS^~(GZ6{bq%H%Aw2|;b z`se^;Aoa&2En>z0BH@p;<*y{tM#4AglNscfDs&*1=7G)r9CfEjBkG5a*LE8xS1{Ip7Ajx*dNtx*qyVYLo%i z5o|rDct{iFhBTu5FDW?Ile(q;$BQnR#sM4)^CUa^M@3H-y{G4002ovPDHLk FV1mZ`Cw>3` literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_white_36.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..585d38326ccd4971141326e376c58b3d8da1c99e GIT binary patch literal 1044 zcmV+v1nc{WP)weV_Y#?Rs{N?)T^H%YE}auamLuc_f$1 z<#M^)|1!FGpHqx8!wln`Vn0tI))Q>k%UNQb;iaVuyMyD**D-Eeim-|t8k^HfN0&>p6zy-dYFOiyzT6T0;@pD;bmElf{y3)9ow!t^v>Fa@oTiW8WEwxO8j z8zyYh(|p48G`BE4%^OTXoAnRV)11TfG`BE4%`HsmVOmLZ3e(fv!4x#tFa@obS^qFS z%{NRza}N`Spaji7jNOn*Te7fX+G4|=VQ;WoBWHF&3EJ++(@qA1t+j*gB<#`1nH^Aq zc4Oq(YQpx|!CoWm*~pm}Aek25TEbqpgY^;iO61JFP)J*k)UkfTw%EZQBWx&o>W>AY z4H5Q)9ju+OZ;IcLg7z)d&CzZL6E0ER6VG8R@06U)@KXr;9sh{%JS&Bm5ixq%eYK+Q!KZI311Vo7m02aBPv?>amG=^ z8ulV#m+3&FyPabTM(ehRHS;@RU(9oQ3upB-&e3EK6JDjZo_WuAae$whpu!yE{KRxJ zZ5z@E*fK5l@n$*64p!3~x%CJG{73}=ENFs$JGst$UF9@i@;Qe%$R`}-SFRDHpqavi z%}k(3K{JL4EBMYAO<1^XWfV<+GNqsy!i1Z7he^sb#v9zgMg`3T7UBjtPfBOlPAh^S z3r7=d*2PC$qNs};gT?zcL%p1p5speXB!3^A8ic6*QMH z1lm!rI;8ZT4q1Abqh*+88J1xgmSGu|VHuWT8TKEWky31?kQf#K O0000ZGla5>W#iS`<&f=pPV6lgulS&w; X#hw>`@9j7Z=nMu=S3j3^P6E9EZ<_N$R@QMd=1gsk?@jUF3R^8_7n#?5Jtfve4HEyeKp>@WP8eKxLPK&0o^Zal3oP9X+n=|J>BZP~Ki;Ig@*g_?K z0<;h!OoS736Gb6P7sokD8!ZIbgAb3rBBl6gqMay;&gvmdGk!{CtM~{KHXxE;VFLJM zsFV?)!-7a|bMD%491DVqc|g6XNFl4BuSAWLy9B`W_iRlhKU=@PsREh zzgpM8Q;c$-k8I8g3*6%pgSzHb+a3vSIHZ>mp79%_q5b|Nnw9u%q2OgTznHF|I zC2tMuyi$4DB2j5S-wf$2YPLAilm-oiJ58UkA1><_8WDwoXrHj$EW9E& zp%f&!q0U$8L}8(yw5HCoffh%i(nU?7^THXJQq{R7oPu&*=IOj(n{W>5S^$s*Aaf->fKF8x!lC8d4T7LksNi_8DSAMQr}1GmRF QKmY&$07*qoM6N<$f@BP4<^TWy literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..7192ad487eacb4f8f530ebe2878760e2528fbc5f GIT binary patch literal 92 zcmeAS@N?(olHy`uVBq!ia0vp^9w5vJBp7O^^}Pa8OeH~n!3+##lh0ZJd7_>!jv*C{ m$r5W0{Noqkjk>0hJ%NeAb!~d=tj~okAZ?zmelF{r5}E*xz!xz9 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_36.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..a03bad27eddf5a828be03feaa79bf4de39ba5974 GIT binary patch literal 158 zcmeAS@N?(olHy`uVBq!ia0vp^IUvl$3?x5s?2iLdJOMr-u0Z-f3|JhnUIFAYmjw9* zGc+(9{2DVA$hGryaSW+oOkN-_!MeD?P=sSs*xIPALWdZb**LcTvKQFXWZX98&I%;x i6;mpswqPAdM1~DsmyKX&RFIUQSSD+W9($^dPS;3(#Ef(97W=l3HOp)IVgYe^RIZWgqh!W9mOT z3^#(48wF{qpQE!0QlkO+<3+WfqFQi{cDW#NBDp4*0%mlAm?+B&J00000 LNkvXXu0mjf8A!p$ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_add_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_add_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..8f744f0391a2312f76d07c0668754fe83e346710 GIT binary patch literal 464 zcmV;>0WbcEP)DtLQCCpAa=!1|L{vuIM=dinFCbb)p^O($o4O1Um0GK_4#Q<&+n7Wb5k$`C zLUDLL585JW^B;m1|JunSBn{nzLL@cagHA}XZAaNX$k4;K4#o~7D@zPG$EFom{eTR0 zY^q{>febIm>lwx;$WSBs%dx5$-ylPoE-Be|bhw7`1*CprM#K?+ikf)u16`F;Xbx;yYNVKf2&0000Cc6jV=_2 zuVoOWb9L^u@cf?OW6nMIj%5iUgb-7W71C5_(W6I`3Ms;qi&>_C%Xcn0LX*fjqQh_6 z#7*ZU8RpFF*YP4|?(B3t1vv!G1m*E6Yi7}1&q1z%eIt#Er2e3aQcy{MP)jMOp+Bgn z6x5xJLgO1ts(cg%vKwzLCd+oadm7Wdb4Eo^n1|w9FvxDJW{0!}-vh zQ_C!3I0J?iwag<(_J@t@lVQo46hb5^(V$D021OEv{t|@{#@9W-28UcypoWb@pFR#Y zHS$~#XPtnllpRu(2i($Mw{@8m+d5OWxaJvEHdjRaPMP6=d&W^^-?t&M$0L5Ivpasw z0=M|-hWT-FBG~xtiOo@S)_6sS7gk5fnWK&_56r3uouJdPdQeqs(4BhFyVjsL^&rh8 iNP;9t2qA>{Cq4lL=57b;A3h`i0000Gs!G)8FeYVPrHp73>fed7zd%9HuJrQN=R|WLOJ}%ncCyVWc8$xeQ4VOqF)rH)3zoaXvAk{>piBRWEAlwS&wLv{xZV!C* z%3guvk6Q)gugB%K%L@Q0X9Y^`xRpTudh$CZ@qc4z4JA9^t~rEeD0KM?QbttAoPVBVS`RP>N=W95h0+fgIFEv!)yrGexUsB00!WXQIS8 z#EC$DF)fB9YdqxvO(L8eq(1{0Xmda*x`{!fs)5>71I0|M1(Ls6>LB@>r4G`cfef@+ ZpieoDLFU*oG$a53002ovPDHLkV1n6sy>0*i literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..f9f1defa6df89b5a7a68df6787a4ba799d3bd3b2 GIT binary patch literal 450 zcmV;z0X_bSP)q8m|@f&vEk zXhJXy z)&q8Jdy{=h?m>-(r*@dK*d3epCi{|HgU+qz4*BYtIwp6bB0wo2#+nm8I>3B8iEGdk zTNzJQxB%cRn_*v)JJ1{dbN|paSFGhz>`QV3I>zMAKdKnfM6N&`Di|k|EDy3@h4PVK zk{o2e3gsieq-8-3jN^&)U)Wy&nw9O-LW-|?GEfU&#WGOH2p`=L$UkuoJ#eZRDaa7g sq|daVQ|=KHU?d>_qaXz-NI@l=ck_!~>**H-(*OVf07*qoM6N<$f*#evGXMYp literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_48.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..3fe5c5ceb684831ab06bcc40d681890a3eeaa63c GIT binary patch literal 859 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q1xWh(YZ)^zFe`bwIEGX(zP)?iYf8M#@sIh6 zB5yb4o?S6}QEDmorTyFjA`cl?hq4B0?Ao}ieNpS*3Nxi^`=)fRTX1XZO4r60>wZo2 z%KZE#Z{mW(7oYXad065%|NC>kxCb-epE^Dz$V+o6lvp*}@PG(!*bSAbW|7Mds?gT^6a-xmTi-mqa@VKe_ZakD+%`@Zp7xzarI_hplX7t#Zmc+sY!f zKxw`7Syq&tJaKvN&#$O5+^n z_ZshCtU3QBIX7$xUq~V2?OUGv9^CiWOO(^T%r@&-SBo8x!57l$26w)GSoAitg70-fYL!Fs4D0pxH?OYK z0NN{Zf#=z|*WcgR*Nc5u?c#q@FLg`a++*_Hs>gHM{%H#_+_K}n{jTkM=8OGCMic&L zzS!!1F0(?iSR7~#w@Gj1y7uXB-q=0U`Qt6Zc*2r*@AcEw=PzHVcePRY52Tj=sDEu@ z)5aPl$$#R%$(Q?;v)+Ln$oB+j`0kTi8*JWri^v1@Jzn3z47B=KyrldITi(a#Ydaq? z?_8evXQzIk&w|W1`muuSKm&UA8<_#!An{+divgs%zH<>nZzAWK4)!TkkhocJrtypa z|JrST^y|!=&hWU$4*ufI45QKb?W29#vZ|nZltoPJMC@EnvB;$6kXs3ztjAWe{+Y7z j83S_qnT3>)zHxug>)y95A}|=3X&5|R{an^LB{Ts5Ixu`p literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_play_arrow_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_play_arrow_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..547ef30aacdebbd5bc27a3831971aa49be8813f7 GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw9(lSrhEy=Vy|FR(PyjfM61bK%=q7O8Xj0w7EPdhfr5^#S_IEwe==vgFzHZ{arrqiL9p^2}oCQR8HlO`a zfBt>_q&-EaGMH-9&z)oSy0%IOibq!5=i7xQ8?znl*Ho#q?l1C zmLwh%pdb>pKr}hv!ldkF|5nzo_`k zc}eR_hl%VF4-<)DT=alRfHl0KMErSu6_?hE1x;YW&OCE+==ML_XMw(D@O1TaS?83{ F1OO`naDo5; literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_18.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_18.png new file mode 100644 index 0000000000000000000000000000000000000000..919a872e0ec9cc1df7151acb3c2b54a5118bd1c8 GIT binary patch literal 312 zcmV-80muG{P)K!nn95@%sxPdXGyf{aSIXBA6WezA`4k%ylaw=>299)frF(oZ_xk#6B zKoQ1V8Ebx0gaOx-u}N~pq$#j(1r}IfyWYOGyI>9l1|2%7I`2ux|6?b+e)$_#YZX=5 z^_{3qbs0-)k-M?m2c$as;OT&Sw#%6*z>quis{8Y1y{p`6R2egF6Gjwbww^eq7-Np9 z_BX#wgR%n!7;{W9#vD_C!A9el@_d?LiZLEPy3|Ten8O0&1@-}7BlnaB8b!?j0000< KMNUMnLSTZ-aDsUN literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..26b9172e8f92ec58982fc5db164bd8f39ac2e022 GIT binary patch literal 271 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawu6epRhEy=Vy|I0&lcRvk#aM;j z_oYR~D}9qDyCy1fvHzU#^^e{2L)ZUKf2Xx{%9e{4OnGzfbv{;^cX%>K-{cBDe=lS z7j`!@ab>Jp8S-k@dxlw2-zIlId+m5PO`1_^*RoAFmF$|$q+~k&m*tw>Jh;C4*^)9o z*H>CorA|B)56j9OY@xoJS#>ZbD-FbExJ^gPGtVbHE_*{=R^&XgdpX!*kL40>)i RWr03q@O1TaS?83{1OPOsZan}1 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_36.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..2040c36d57c73d78ac8df7e70d36b149e56c69f1 GIT binary patch literal 442 zcmeAS@N?(olHy`uVBq!ia0vp^IUvlz0wh)Q=esd5FgAL+IEGX(zP)2U=~aS=%R_ca z9k<_tvk$oV&)jBu?|o-y)uN5n!9&~h1XM)O{Wr5YMd2w!n1A1*4Z|~vo9DkI@?@toGi!Dn61Hgqs>d#bakp<)qmNa z*uU<--z%v)P*qjoaV^i&#(D;sq(Ght2Kb*=p5-d)WZxml6Z}hoa`ODmBb+3zaXH_! zOjt{N#f9Pum+>DKe{qq-jWm5k(Mdw$!@bNA)iifV95{|oDJ{d7+|Om4iN_HffybF# z#{GOrhSEOdSc!&4erK&ITDdiNX;a6ov@*q7zu<`-C$bg41zx8y)60G-6Z>bFTP^^RFBm!#a zpx7OiZG*GLaU=$G`u3%Sgyq|n*K?f2fEwSxbxJr~;hV|{DT}>c2{D&O0CkCk!T+cw zU0L=(iYAs&e}{>437|d`6(Nw~a}*)&0ep>GAQ5|@B#Wr8r94h%3H7?Dh=CMupq40q ztK>1%6b()SH8O>IRLbEWRI5mwffQ}1eg9V-^gwhZ08#LvX8JaDr$Iz zEDFBl4Ex3y;pkAD#WyI(@(MNfqa(uMs&6S3{|c*RmxzP+w*3kle95;D-Uy!clJ9>8Es~H3IE!zAJI&9a;D@3e7Z@LkivN61 zX#>Mk+Foq1BgrTVF0qzlYGNwKY^bOlqe$)lf|dJ{UMI!wh+6bqzh8@18zk+dXf)UDAjLvsN|p{t6$05L%?Ktw?Z^gaZCQV^>Zx>oT5B!UZD>LPSm z|L~VCszm}4VSKu%ZO@sc>73z9GKG1U!+E|uoS*N^M5!=g!h{LqKXj94ff8p_aHw!f ziFtB#wL|6=o7_=9cWf}!N|_gY;@|neKr3V(v542)QzX`0ojyKemomN0(|N`@_Bkcf ztl6p6`NkqSGQ^1xCqtekuIebI<#is{EY>;WMC*)uR$b$Z z(g)oNPHrpSfn4QL-e6kR;0(D@Nb>GoKwwK4j`B+2oi$`B^GkO6(b* zLPzpSF^b0NX%vSUqI4L~4#ky}qMuz4Iy=7(y6gF2Q~ohxkTt4*QK_=7cV&)SqNEg^ z3^T_TC*0t0%L&`eGUC2MdD=21&+2^~xs(oqsFZHE(qX9Np|QG^_S>&?P@~inD!G)> z|AW$(_ABiNO30vw6u_#jj0000< KMNUMnLSTZewp6SD literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_send_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_send_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..0c5256413cf501ce0e6d05d6fd8c5df7b5f46424 GIT binary patch literal 446 zcmV;v0YUzWP)8< z2n5)nhg_e8BEU7{6#FCu5M_nBG<%5hl4C(YsSv;wV-$NMWFC+hpL0YvxyC}~0g2-# z$}+V^LXLnrJ_!L_GD^|^3MFtL2&fTqa7Y(9DG)LbNRq!1WrASK*4^FfYoVA zB>TAo8tiw$uq2>#zlbEDL#UJn`j}yz6CRvG3smWoRnW`;b8K?E7b;$NIBLw*XKyp`n$b2k^}JV{w_su14YLr!xZ`R8l<|1laxHB>L8(b z6O#%FB58#LFM~>m3nH0)((5w+q$h}^|12!{C?ykeN76%7@L^L4Q9&dnL#L|b@YE}LOu zJMC#n8k^acXlLh~uTE=?+1dW*fBu*A@c(=ypU>y>rHdR^vx|BfX`-D^^zoA@aUu-y znGT+Dm3sD2K|oHTgxy@El?Y~y(8eWdDUrQcLj!HZuqsX)Au5zU$_Nq0E@945Dr+#P z<_R(E7NeO;45fkq`w8QuF7^_T8O-7!J-DHVePnBT>?DkvI;m1JEafR)Xd=?%rW2>Vr%>jxoI#v4z!If~Dq=V#$~L8rvpD6Xtia$tPPikhDB=Tldq;t+ zqnrWk)K5_9VLLJG5@n0h$7$?RCwp)gJKU08D5QgQy&+%rA;@>q(MOr=#a5zNHOeO0 zj}usROwQmoR@{(NDBvxrdQG03!(#eL#a9-|S!^bXS)*)_^Ei%KN8}D}V#YPOg?!qX z$t!Z@9!mMfbb47Jcd?OCl8LZR?&B!Q9FjM<&Qu!Z74m3hvghQ;J1nG^zkOkzyv2GV zj2mICyvJe29Z+WA3JI5$Dahp|Ed-P~n9p4Kd_JEQe*p8Nuxfxg`z8PY002ovPDHLk FV1gfTAL#%9 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_swap_calls_white_36.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_swap_calls_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..140da28a8c97a4e09eb350446878cdd3c97bfe43 GIT binary patch literal 827 zcmeAS@N?(olHy`uVBq!ia0vp^IUvlz0wh)Q=esd5Ff)0&IEGX(zP)wUdrG#%@sHIp zA#E?$T)KBc zxE8qzczxLx;Ih=s{qMHI%eA(TADfE19{u_^cYgK9L^-*4M_JB)wt=C#kTp;Et13@u zTs~ubR^#uNq6Sfx&%0hIy%67!#~m)AzSHnij@c##-LrhBi>4}hhd(j8sy1z2TFcv~ zvZr6`R{QAKo@KB;CUbiIiF&nZeQ6C_7p*^fDCh#u2Kz{d`%La%bxhAP+&(Ds)bym8 zu(#vo%|<-Ib^W|LqQ3mUXFsvKa5isK$b_X6Af#{~nU6G=;ktbQ7 zP28)JoZ>l4_E=qtv5b<+JC4mKzRirBl-73F>6(wm&i@ndZrH4Hmg~36ox4+n`8%rf z(>-VLZj-%vZi+GQiEX!lDjQ|h-kB-&^h)yJEsn1(N4E->cTU)4Q)sE}b4h2-f&E9m3I~}x#7ve{%VY~%FmcEEmH#c* zE_8@#1`8zc79ZIvI4y>~aC6Ab#7WDNI&D?+daRsI<|Z`lP;8P_%M=S+AbV3_YRi$e z&p0=kS^HedS>qsU+_|OHbAOo9>H|?gku5qqU#pm&^UT`!Go{49F{qa1je)1}CZ^dl z)OPCID4nnT#1o*f)AO2i0^6*VlTS7Fhc(G9TOb+H$n#xuy>*JuhLTxbs?(pc{+bu) zYj8lsgjG9A_Wac~QB91?7Gy>gncfNB+j5nK*~dM2;}fGf30+^*GF6=o4tz0D_0Chi zK4W1C>#rm1_ZWgNT+!JXRm2l45`I_l))C#q43{r`S@R@xV|V?D!ZsOSlM~W=WWUWm giz8_FU)aa=yuMyy?&icYV5VU3boFyt=akR{066=0761SM literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_undo_white_48.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_undo_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..8745f69ffc8b4b224b564871e1dce2bd87694240 GIT binary patch literal 815 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q1xWh(YZ)^zFn#lMaSW+od~<fh@ipz%a1GX+RhReD(Q_6v&w`Bq*R;0f-iDwwMG$Rk zrFm@TyNB0ze;4$Nz2%%@QXF~SQLlWx`rcQ}_cb(rom0Q}sp)sj8-dvoS1Kx5vlu5P zif!nRu30<^Ql+g!LNH!Z9$3B zU)hyP^>Y&vBreQ%aVwg=r>sBFx#6FR(cJA%c78u2!+zvx-4&1h6-QjZZSULZn`)yh znKB_SdFGKh*Ea0FZ2LmJ_seF{#SO3Cr(eH)_70o6q|pH$v+}j?uY{ju+sppKJv{Pk z$C5stO$#R1to)``_J-F%|CUm(nr-viS7M@D%N+JK=4~msbj0UzlIzy3$#IQxCi$0| zd>+`O-dr7_U+<6~VV9YhR<{3*sP1g_1(O!@dPmJGtx?UkpKYk`aDJw0X7I71<~4g$ zmsBX6Gd0P~Hv7Cf=kA(#oeTPAo=isV{Hd=GL@X$tyrAcyV5HV;bD<9A$qRVOXY1@u ztl$Z-xtMVM)FsV8hmS7IMuMR_BJ3jd7iBM1pIxA_pkfhUzi0k$3n0U=R%h+{9uZy< zPm}FUTl)IhyHswuMeUa~m(!T^LM&5OoL|HvCFcIBd;C?88kIWDCSJSu(V@}hS7pdo zJ7X1~q71#vwQ~F--X%+4-Id`N@k$9wy{aXtEvGTp~bKR5^nH` zG4KtM0O-ddnU zQb`a;`lt&^Ae9D1lgfi4NgALik`5?>qy-X_^gu$ACP+lm1r15pha_##QIb9g=&=Zs zYJf&bbwDGeTA(1Q9wXg%|8kB;^jz_DD}oI#1H0 zJ<`KJ(z-f`2=~7q7H_yP03yO2dP5u{A}sN0h~s&lXS;6})w52>;+iV}0000*ALSem!X>zFYQP z>{-@X*0uCv&$Ma9Eu7D8Tw{~c`@lFqP2%x}%xkK4+CGsSmm5Ucd^eSS3@Yrf$?f9X zy}mWs{)TU_;-@Xz(@dFu9&Fp%=5e`AhkKvFDofXCZaUghJ|I%bXA+Rq^63MTMm}9Y z(#od|NHY2~0ZC4sIY3e{$N23Yq27ovqX-Eg=@h{MB!gzy1IeTr`arU1hJ0_tG^QE+ zZ~IbLHe6kWuGaCC#w$<@K4hj6=;kn04|J&F0)?b3OlT3O=+XgDcU< zWU2w@te^-BUtOIk%Ou3yf_b?YYPSEpeC2RWrsRP?8IcFJUA*_X?dtMW=GES(Il}s< ziSk4&h@Uu3a*dU)bwp@X+lH(yI*FkfGY?fnZ8PYbW|(8Gdun0?*R9;o>9v^|)^!{B zmfgzSXTFSijn`7ygqH0q8p7{9mfCzQGt=pMhMV!Mi#=&u+YdXVc_rZ2gm&|pDnu%I+pP#P>K4HlFJy9Fh}Hqc=h z(_+T-pT7R5)*n~;gIIsX=r7NL+soj&s-|53NZmO8Gg1?0X4a<8oPN)5L5t<8 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..44c28e2f2830f927973beaa3a143ddfe439f20ed GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawHhQ`^hEy=Vyh zQBv~(_A|Uaeg>M$g-&EJ3;(E>F0WfsuqEq@i4qW8@}AzdO6rx>m9XRe^SrNqJ^A{6 z_JW14-f=$P%=XJsxKGL9nM=c&PKKGnj7I8ADSj*`=EzL26jUe%O0+bb;bi0#P;hAY zVbJ!!)MTd$)~z_vMwRMV&l@06QMdET8tK zS6wf2e{J2rpVRb>tTxGUT0fq;=G&TG_5WI4S8m{)dAB^$dRgTL-I=+&b)FqkGn!qs zCTK&#)F#%|B03RE6Ao&za))U~Z16hR6v`!rBy|)h#l{_`d&7A{)Q4ux{Irg)cJ>B>G(_NO;w8dudCyigSnCKRr32yb)-3ul4Kb zjq0n#{f^5fnO&1P`C{_yjphe?xyxiCHZk|lxy*Lp-(h8+83sVJ!RDecYMJkg#3?5= Sh;RVIjlt8^&t;ucLK6VF+m~tp literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_voicemail_white_24.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_voicemail_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..28b8e936a05146771d8171de680a7cdefe0c9b2a GIT binary patch literal 625 zcmV-%0*?KOP)+>1hsE%qry6oa@5MCd~ZF4`9;2to*yLg>CqmujvNrB4u2 zx@r8n2-G?EFOwW>7Cql?a_;$ZX72nYL0}k$VHk#C7&E{MM|9{jWWxj3tGf(b3vc zhW8u$R4Efurb>hJV+ZZ{`&{GjQ zIU^ByP}+X$`}9*pe(6VOmbYGaa{3~2r?f?KT{JuuhfYpML_RBR?SPikJoi+5cXC=H z@?L3c1}ux6a@|AlDrcu&RoZGn5XjSn(geX0H`!+y&%~UZ)^;`ia97lLnzvjDIh%0W zHx#z*@y83?$0Vi9{+vyHAM&@|{=LTXHgH!QaPJT}#{1tSj$|I63^&@8aYSW$%v*?9pyNI-ADL>|>-sLM7v|Vmy;M?r5e;wn&#k^ZK z?r`{UvXh%-yV-@+yjzOiF&*5>TawOf``*>4osui6aIyg93wS$O@DB>VW!Me1A;-Xg_qz+${PFDqW6&$3#4E_%y zbnv=}gY{j6iniE6ak1cF>uoWDF3Cd*QgV|sB+r;%!Uyin$vH`pTZEQdZn@<~AH{N0 z(2f|sFvcFr>VW=bl9Q}V18TS+D>Dqo2Q@GXa?+%?-5}*CNb`fCc7l|npm~fZ*C^Wu z5{`hnIl+X7bdOqika7fMR{f;4M{)C>y}j)45>;iFT1EF8$o5s+_jZ)MJ^{!CXGke{QVm+bb8J@3?? z#SaR^(XC^VixiR$UR(8({wGoxj(;z^K_NNljM)FbAhWFaX1G8hd0~yX6Cbpw|0U|y zh;P(lgAA`IW!qh_di&#p3`b=4rmVE+pocR1WvlOQ3Q&vHPTzoRA<;pGeeM(6>X}Xh zsylt_te)>_K%-7ym;G~A4fHGjWPh`F$v^c}nq|Lg$z}g21?Yjyenqy|=%4|a{jt?| zIzDJZHrKVz=DIyLXn~zF_Ze%%*Z8j=BRaS95<3?A74|xX_7O&ty4On2@XE3V9dzP8Jcq(p`*@*6|CyVZUeYC9;eb zA>``#g5Qc*fu2;h#B;V4-S|F6)h@MgH|yvD-!%2rmRDRQ3kKsD;oImHj%x0}G)R>vLm+2n`D%IHY!LVa`UVo*UbQ@Y6=< zYHq9>p;a}ZKk<_RaB#(+x@oiQ*R8nhpIQh#R@rYLOj-yHs_f4Y&W9J8R)_0G+6cQt z3$@v+a$i9B9{&0<=H#A1mH)8T6bzp1I>>IT!Mw z=!;z}Av9TI`;^|o99c$eiw!-ho;GD$j@imfvMkVNS+E+QNuHB-CB06@StQRjyQ1eY z-l4f~Qx@)}?va6eBsPWf7A}8DtJGRpV5myXmnpVYr#Lm;e9(07*qoM6N<$f`lO}%>V!Z literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_36.png b/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..96c1f982fb1f2302c2bf193a0b7b3b107e7c8b73 GIT binary patch literal 998 zcmVy>`H~zf4Dcw;Wd6S^LlUmTs(i}XG{O#Bpo``-!T?t3;aEywR?D>OhlMrG zO&VaO*f7|nJL#|zNHC!ZjwcsZf`(ymk=v39D}e~Ro%dNqs>->fz-$)cT{$|LBfNj; zNCwPi5#jDOekZIN#U#LN7Lk4;&s%I0+yPG~0A{g>{Bte*KybS}=o%)oWSD*B_<-Qb zw77@KEMksOV3(j4xxzI}W)XXoR;mOw>KZ1qXketfSSP5WTbRtEq0#PV8@mc8T*71) z4UYI2b?iQK36ohgJZdjNJtV>$vKohF`4YRI$OX@}?fx+X#Gy4s*f*#no02{*WT|KZZ@}YOXiP^9o z7~B_n_fwe7Xo9^aEby2uX@d2K-hCZre`$fqi#5kF+tCD@5j5*sxba z?>?jZb$@S+zo5U<1KT7Q<5#L7J+QG@|J3Z$1AAD2En(K71$L39(0i|@j@d~quor~q z)rnbI%hJFsO#*BLvoCZk=In7=U|q&KX0Pj5Fzpd%EMj+3!xHxZ@_gT7Hm~8M#0X8| zTxYQBP5x)3eq>gL3CwC-pX?8R8v(C)`+3zd`#Ra5YA3ld!W`dYcV7R;_2;ph)4v_! zTFTh9>)*gKh21P!?OTrCBdD|5H;J`T$8J>nw!T(&uv_CA-5W9QVS}Ka(Ykv)Q1;Bvj&)AL*)xWBnY?}36_`H|puctGnBkY?Utm*Dn!LhGTO4ps>3fP%(j zR(W1zp78c~Qs2S2(|pLENR??#<59*%PNnhi=@?h0@3?T4m(zH_d(vL2(GOd)H;U

|=Z_SP`nuw_2tJjZnZ*D}K8VIG#K%fmd(!#vExJj}!X1+x*+ U>BgO-%>V!Z07*qoM6N<$g7ru2O#lD@ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_back_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_back_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..e27034d67874687a900f0f960c662e94cd633e2a GIT binary patch literal 194 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcgIz3$+Ln;{G-r^K&b`Wq0WJxHR z+hbl+*u(m6U6udA_c1Lg>hl;G7;?6Tmes9(^C#@)&$XLAN2fmDK5_2;oXs^qKRrD? zT|a&wl=0u{XMX3o{EI(zZSFU;t5*oK`xGb|A7l~sF+e3G`eLnqRNcP#_|M_{efOCe b7~U|>UYh-J>#;zfqZmA0{an^LB{Ts5m>*B+ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png new file mode 100644 index 0000000000000000000000000000000000000000..c19c19d2bd2709454a29d9140d5d0a1ff51302c4 GIT binary patch literal 152 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw;yqm)Lo)8Yz2eB#U?9M9(5ALd z&e6u>Lico@h_6j*yKfo-6){+xJ+uDO)G6!2y{9}N*bUL6vf8QhENI{m}$MD#tXU!7hq{)#VD@8yT%)q#%h=qjL{V+cp0XG zn9Scy(CUQb{hm2~oRggA-N5rpo*_B;uo8btN=iyfN=iyNNsBN1X1}t-XI7cVcF(AC z2e>U&kDmb#7^@DrPfGd7ST(>6Qp;);z;Sw{mI3pAz=54qzF*z6pfg`omkOMiA!Xs6V_3Izs(`paI_M_1%P^en5}`*HO~IFo6)(A6`QT z9OWlUI!p+Jpnla~kbgcpVO^=O0Fdva1)E5A67(MHI5ZeEvKKgugLd^Q; z^U(=0>!Z!bk@j8$M|}x!6(Is)+)-Zu%n0)l36A;#;5E?`tld#x1zbUhLWo}Q&?XI7|%4q$RGLo5C<^LX5OD!jU_UOVe*VJ032pBZ-8+zcYyIc13=C*GRIxY z9bml39dLy2dH>_9ahWvJHN5wd6tiMj#xoi)XZUZ4)Y8I?DtCvJ@_~a@0mdzM5*bfx zSid^JIKf@I`^ea)%L;S<`WTsC0q9o%1yBG5Pyhu$0sH~z_U)b{&Qcu!00006bj;@MjOPS)^G;^F`7BWn- z903~{qnJ;er3n?_G;^LD#bj9@b-?%hi@Qm>OZ=<4l+#5c-q8|ez{Vo;^ITvVD#S_B zN1;f7{kp=wxc3AJILZDOEQXpSdm}deqyMIPJ$uaJfkLjz#ll}`4tu6`GINN zT?-p<1gAOn8k!GqI7~njGtT+!GB_WmX)HZp5MAEPPhS`)HJ}p*W7odaQA$9Zx9F}J znE#nUbmP*PHB{2i@w~=5JU3buc1fP)dY&SArq1cITlDc34DRdW%%~vS;(H#vE zP|X<9B+CrWSJX3&^olC~0d45IP0SbP47yhT0r!wT5jQ+vv78yCTYdxT_=asLn(T()CpMX{9)?1pd*o1DS zcR(A`Ys2&9d5^T)JK!YJZHx02_mNI`2V6%=Tb%E_rR?<%c#PC;alYaJ(j)JH5v0u) z=PR}$z3>j0Kx(i!U$GkLgLl9jQq1CfMI33?J76BE+TwggHBvr!K$ZFV;Q}0&klFd+ zFCoV-vBmj{HNk(0N07EyoUhm#{GZVwq;`w*ozEr@y#xA@(iZ0{dXTOLznQyhalZ5E zJQe(Q`i;f;&fDo$?|^!A%_irEf1puhkd9lLuSk{hNU7*W8n!fFF^qJ{U%-BJ%~s}b zM7P&pK%7~m^A_eS&LPbZ^B17FgOp>b@%agINHmnk|-e1g)*0Ojz2wdOto>R_BGjdIBJXIQoT#w1agAVtj1 zhj4Wq`c^&$tz{pV`3FBnxWrz0(O3--C&_M3(90uU z@PS$KLx(xf{_=_KEt^PKnGK4bFKIp5uVo^$W}WlZ;;Gq<)HM|D(3byP=nREK5xj9YCj zXZ4;c^MsTEo{%KK6OsgYLXrSaND|-)Ndi0}Nq{FL3Gjp@0iKW~Kqm-*EjDXI0^lDL zIRA}h)?$KX0zm~peg*^rFhK`EJ`+N~i?ty@zMBO{AV9Z9&;hf-OFIGrY8pWY4A}w@ z2%rjVgS!@IROB}nD6JI+t;)%2>^sT0XRRHgMP0a*8xn30qUGz zFb%i6p#zu@0ysZDBW{1&w(9^Ugn+s&7UuWi>umI|V<#1WpL&##`GI_z2kxv#I)Dga zY*BtQlHVOXa?G9gMF0SShx5m6GI(s8ExU8~sQ{hOwEjqbW}gZkfA7v75dZ>#^DpM> z`-7Ex?)(WI5E2$U$RCL1=QA3topR4GBLHMVE0RC)*Pc7U>QVO`b2@agjoJ1zpvoec&C5=5C8(9WrLKT&$nPtms?-b0Z0(?Gi!$z^lp9me*)ZI5n!EL z|0x1EUnDFBdp7xX3BdU>VIF>oKPv#v*9i@{E_qt0RZ_3kn>>}@D%a^ zpyum<&Gxz^p8-Ag%0B|{s~Ug_KA!KG87zlJde)+0000ckhC!>El+dcPvf9L-0UzeW{AC0!eS;Am2bPN^T zYKp>-whS=&IGS%T3}&__28`Usf{*vNRnVthnCeHGBQLJpoBOdlNs&!u?D>Gg+T)9kq?ZEzbwGz?m{c7ie~sZ%M^E2)%p> zaoZ^3@_f>N2R05uf-fPW*p0D%A}Adurpl~3Vs>wcYWUlBh()yv%maNSB-`%jGXpJH zQ{gNjZ>c;~@+CIW5#oT17c^x(Onv1{dcR?5ZLATRJ834<69jYcF`SA!WP~LsYu>$u@MR z#8V|_!L(Awv2_?NacpSNLN?pFq?scN1?A`8hSn~VXgpIEI{+fjg(-1%^{DOJT;Y^U zF?X*o`;!=dw_x<(c7sO~%9VgD)@(m946hN4>Q+DFr19OF<48rrp{JjOZJ<_^8Yr9G zkpj*jr+{vpM$Ym8+F;jI_PK1q zU#J*BP1!Id$6iz}1gX>`R`ahhT0-koT{xJ1B=DfpdM_cY5!Z55^j)f*TG3c_H-msw z<%*(>Kl~H?KGRzWQ4Ku&L(YoYzP2g@M@lM&Q2sXRaa9v7qH{dA)Vz1xXdy00y&ZlW zoJ(qFTL>4xj) z#~Uup=44UoQ?4))5q4xVBFmDhw-;)B2+zNwh~@bt8k{LX950mS12njWE%2g55>;f$a!bnJ3^a-8Q&a-BDj#(M~HGj;g!I zhT#AT6Q-T;yKcMWxVr6%K>-T8JnM{J*Dz;?qQ8JmrhTEGeXj2M{s8XwmOl-mWk>Al zC7>{A!Js?kent0y!j#j7)u$d%bOX4{$I5r!N%LksY_|!UjT==ctTS%23A^nzW8O*U zmG474I|JO{4P{z(%A6@TiZ*tWDRVyYht{on)phLwYWDj8L-itux0`9nrkixxLt!a58z9;H3Llg znMwfo(S8319JESh0Q}{te*uN(pi%&sQ;0C)bt(zquv(a*vH*4F5EbdU*GfFjIneHf!T&u3Z-OsM5Qb8 zN9#sXwu~_BPAVY?l86#YGl}X+VTcbxx}8}LN{TF!!Usi2NR9HQ(!i)Dh@fn#$LZ#) zN0DM4^n1SN>>PLApa0?|ZVN5bX`PL>>#;|#yg`HVdhO9;yN%X)$1)4e zahAIR$6SncC99BF@LgwAZ-Ucr9La5>9$Ez zuPzT5D@wRA?y=flY1-`i;(?mHDP1obA3|xo zfHNKlUe$2AKvVq8umNI=Nv95!cu1aM1;hdOof=T1P8fDT@VW+tfsE75umxh1=0ZTz z>}FU4vCB0l1G-;7!ybr3=AH=!mJJ%$w#&_B5WEVVoGEHG9nw#g_k@h0lZjz@&7h&H=XRLEL&XTu{x z7DNX;p-xoL>MXFocpedoC)(g5QGpxpi__$369s`%5FN5WPE_a;kIEOrBSJAm+e{G^ zzR9+v=Mf=2(Q1vN3f8DIEsqH4hz30_5mmCpV+IQF+$;(Jr6B5ao2atgs;@9l3ZRn^ z?Q*%O!d<4PFi#qwaJ#%?`^AN#N;lq5j;&8y7Dt?ue5fDn_L7mJig&i9{s4X6GCsRI z>9b7GA}3V;66b36zsh>*{kt7HAOQdX01)*5bvpv_fm;d$2@)hokRU;V5F|*DAVGoz z2||z{L4pJc5+n#gf&>W?BuJ1TK?o8gNRS{wf&?K*kRU;mAOhFlPsF?ZQhopc002ov JPDHLkV1l-t*)jkC literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_made_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_made_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..844ef86a07eb6f16a6b8cf0ece63597a6cbf4232 GIT binary patch literal 288 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD3?#3*wSy#70(?STf%JbuU<+sOOQ1ULk|4ie z2Fp($%=wP*IKjWu#;_v{D7?Va#WAGf*4wkYMVkT`4qQJgZbiB zt5&_c{5y$P>d(UmdyYTh{owft1W$gN&m&Wx_TWcz<74B38n#L29X?5V*fF0>SNO@J zGQaVO@dP3T9|zX~!N2WiKW0Yi&S&0NdSE)Ae$Dc~Gu%T%uj>D1cp#wbveQev9_UsE MPgg&ebxsLQ0QT30lK=n! literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_merge_white_36.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_merge_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..9419ffbbc9282ca15912f8078f23cece12d5c8b8 GIT binary patch literal 435 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q8Ax83A=Cw=&XOR% zUr@7>pl$TMYNV6^shaSW-r_4bluUUPr|OJKcl^UnXRo4s}2rB2sJd0m~A zX)C~Q3R@Pmz@$Q$im9{-D`K)s9c^>}r3a36mQP+n*rE@jqT!3h^oSf5^o59`J z8kP(2R&ZSeQoR)~YQDSHo^M$3?TV5gn@wxRf#8lbn~rtsRy>pxV9e@K`gKY@D@W;7 zb=UsMXV<+b=3n&h*)FT?U#q{FhZo)!{c0Xwc{@6__zopr0O6^zKL7v# literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_missed_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_missed_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..b1321a9aed8c39cb3b56979475c93b332809e5ac GIT binary patch literal 355 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z^LWv;uuoF`1brk-@^_fu7Tzb zw>V$QNHvr>Nl6^h;%?b@3hzyDpj_F~@So!6qW*KUOo-sKH z=fO{of~M!n3>*{q8-D-VyZ*nRf;>aGdc{5lJ|MvelRv;YgTG*+8whe)(o7p-ZLmw>|<`&pnIRuI5B%4bK0R}HSA|vj$Z?kEGO6x z6u2}Xv^EGU0L{V>SO8R!=)aHo0TT;{fPzB<10yoy1Mg+)Jq=N{cQb*3$KdJe=d#Wz Gp$PyU8jWKB literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_received_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_received_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..417999c85a41e3c179c644fbe16a476f68cca602 GIT binary patch literal 287 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeE3?v1%WpM*3l>na*S0MeL5ZJ=m`x2;*yCldj zn8EUs`3Jt^yvKI#Sm1QF94I{B)5S5QBJSj z_KcX{q9!kPZ9lg>-0S6Tv-bOjRR==6`B&U>=hxui44Lb@;Gb{8Y|$t8SXU~Z6Qc*2mt&S1%KgVBMHp^RYyNazhn$Qmeg03>7( n*}#y)P^VCpcH+aQATROV{f(_g2dA9^I+elG)z4*}Q$iB}O<;4J literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_18.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_18.png new file mode 100644 index 0000000000000000000000000000000000000000..90ead2e4551b165530bd2430b3d69c34263c5c4e GIT binary patch literal 597 zcmV-b0;>IqP)a~F^ihkCNXidBsWB>X=;U*@F%!%#fVZaU}txjgmm7*kE>_wfD zJ4vghX)Y+W+A>RYW}(s9ms0kgvz_-nXXic7bMt;aQYw{7rQ+a|A;-#I(=OY{5am0Y zWfwW3^~f&rM7t`x_(`-r*+q_ML$ZrWqCJ#dj1g^AcJY*GIgD&#kT@-}i3`LzE}J+^ zoB`QH3vni76Nb;kX_ZZk5a)z!;v#YO$R>6Z?LI~}VVI$`08h4Yi&6qS*+(ZU3-IIu z>zHA=08g&aOR)e??y#Lg0iN9A2}>4ekZW`hc1f;bc*&AEHpw*(5q4XyVR%khr(9zf zd6rDFUaoP2usayJMLpAmosw%DC2WCxa*ZLvKCxA9QO8@t-q9$x*vU7-#@QgZ=w^|y zaT*l^!(L9ZMYTZ>h2FDG5%3w|pEvY#jAo3IgrT28vm8(f_+%;eg;zXakY28EhGta@ z!!U(@aT=p#@W~Qqp8cv8YZ#{3JsMO1pDg7VQ}r-hr`Qx-`VXHhbwLu%tSQXU{ z2YEroR7)7z38;u_k5;bnkuu2+*3!Wc)5OWiCJb$y=Ml4%G9VW)G||O5GCXFK4}9eZ jd2$TkDV0j4QgQwO?=x#gyQpL<00000NkvXXu0mjf@K6c} literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..b0e020573d37e8b4acac23fcd3e01cc39531b5e4 GIT binary patch literal 778 zcmV+l1NHogP)pE0}6<4A=MUgDB6h!xmw?$P#D_ykG zL=hFSC`v&PZLuhB6vP_@=VGGKX8IHCrk*(yzZvID{vUkLBLzVa1VIo437F3S<}L zr)ZZ=%%^~hA`4^@1GpNLMLfgRh%BOnyC&Jg3*1eTJrr;^UH0$M-cTV>3Gwxo}CTrME zHM(UD8LF{E*6;z(an~(-ID@NuOqM-t!_8Bc$|63;MUD>HM8qB5B}b?1Vi)7f(<#eX z$ao5L$u=TxQb~b~>|-0rie%*jX7ZA9MV8AK{777pFXRuF5qDC4;R10P`GnQPT_ln} zi1>rJwekty5O<$e`GbfH#O;+&SVD=n{ma+#35SWhOPl<`Y=(&ICz3zdK)H?b2N7q9 z8>LJB;8XI%J>VnxgC5FVqgDRk80F5=B403-KPmSM&GH4Gk)zykn&k_=WsGva(xNKR z%J=lq!!$J>n@MtxRyiWeBmVObzthK;OjaYYha}heSPsZiAnp~{I7%Nqe8pU5F@+|j zhloQYc}Pa@K$Ze-MmR;g(m@mbBpGEhkt!lXfoc?4pmfkoKgoXLLnR_Zo@xy$Ei`eE zWcOI1GIWurdLv2?5xc2mKW+LSy2w)#rHf6Bk?aBMi1Y@XTphVqhBCv?_)QKhv zE4e})XyOpDiu1fDO*EF!&nPvM1zI9LJx5Cecy~F=}h8lwKtS@9n)MRxm2`AkqpItJs@p>)C(tu-V-#=CId=UD(s^ z#Zy@d`v;fOn~Tzu?OJHHNtIePI-lk`KN@Bx3G-g)`+Uz|m=FBkykXu`7K_DVu`~_~ z1Z4r$j3}CsFA0vr7p4ddb45K=_{;=>kNJmsIpZVU0%^)LLWz`4fe-nOMmgjIT>|g$ zGtFS1ZXE(|^ApYDN8W0_z#v8Txj;7;?6E~Um_R#sF$;$xalZoX{D6r(A?{D$E~c{O zM_>?haY%a$6fv1Q-U9oW%qwq!3ryzRTflV87q9|W;F{;GFv0){qSYiAAj>K*xHezl zfJJ&yHS#`7{A#YiA58NG$|F%`I5JV-9to7sbaLM;flIzZ1Lw!X3#^Fu{wYByi=R|$;R}qoTB8JI$kiVUUtqx1 zx=B!Su6`5*yii_yR9b4GhtSXus6)G54OU*Fzb<9Fuf)`*nQG!IEfB;+M}w za~X69{6e&@G0KTnj6*#FFeADVZuofoh-l4&E`cLDWuFO3wP#-rPc_|?^a;Rylnh;L z@)wd48zfOOJOnKQa*Rac43Xn8&v?osa%9ANUyhGPfeM+%FRSSkfU`OkhV}j2l~kBT z1bVSYwP7Nn+I` zNiohkFLCTaw-vAgjq*RZ@U(}??0O4qVKTS91=2W}ibKjn!0?Ng1(Y9wI8QK$-KYb`{Uhn?)RPho%_dk?m73~Tu%=tI7}V}00124 z?C=wxX@94PARoE!>+=9WXcy;Tdoc-IpJhdtalrnq=+%iH$`tmhQ68m=7}Ca^2t

MC;gY#}3%ZI!JtL3E5>d9pU7yT7ajPn?IZGir-_z)sHnQhRDwbzY8 zZg_K_Ky)5T8mn*{(z#8F3p#I;3q9c1X_p zG+Wh|8e^~+bJL=gw~OPVn`p_ABze%s%VGZaqMPLf(rsWnitR(B=Ht@_j z#b`jFl)!Zv5Ku+KiXK2TGc+?GcmF1ux4P`L4EOkPTLpLQ=sDrp$dC*#_4Y@Ao|IYN zE&O$w?}UxMJ@uRyIOY{x96+JBbH3OzJiRhhWsuP%!b<3o6p`2I$+$);vwy4*O=Jo*A|H5~9PA zV9~Bp;3*`adf#*+#L(XyDaAHI`5hn3s_Oi?E)s-0K#COX8 zss$E`g73x=H1(PuW*0pz(Ep~u&QXqrTe~YpXHlc@e?A2Zg4Y%_hE7a2u8H056GaI~ ztu$G0>|k;E%YEGI?O zv!=l%Q9b$xi+vv%sz^{WxTmH!|Msvv++Kqx($sM;@$){Ec+`Xf@sN=_!oM*DiK&eU zkSufsHo0)giM^EGb}Zl~NZb=4ufr|AUpx|)gfPm*M50ak?q z={ryfVZ6-Ii5KRHnoPz4hv~-x?bp(^rZ10xYa@1h;6;vM)t}#iC@}owsUHfVJW-#? z)C`&{TcRaKb0wlxiuP*s-$G1#W}Puly#9U@>%9FT2TOUWPv0PaM~2|F{|HLf?%6S2 zP>+r3+2<3+`;{2t@~4759?~$`KVts~X~f|BATVI?RFv-q0kKP{iMr(_MG zhJEwgfchtoY&Vyh@y^Zxz z1-HvDu=X@;vKT{MFTyH~@%(vjk~lLGW4rAf>T-7@aG%s%_3_PM{gT?MJTaLm|UN{RBTiJe(t_i003&dU?Axv@1zvFOYdq`O(wzyJf2(nX`k6nzVnqhy_=X ze-88#f^xrKX^>vH9z`w4g3#33LKI1bgEhdMqDBrbHrYe+XNV1<(KnO7wP)xMO`G`p zd4zsdU*yOIv_xvzoS)LYtznmc@v5G4yt8lku>}!v;g9uqsP`?Y-Dne-_-ma;v!PR! zU)1_RjQ&Tj!L9MUbq#HOxOt`E=7V3!0fE z%Xb?vCve*|5KKETH=I~mB8;JC(03Ho^MQa;!ir0LAEJm?T~d1VfC3>c>N{hkXc{;d WUx-xwt%d&v0i2_U1KBRb^wD=lt6oW;%QS1o1=daUAyI8~(&3 zd|u96v#;i-{{JTZcp&}h>FMeJ8GvN{`tw#N{;ZEGUD<;p)-Lh7=#>`kZ6pLOOe=>Nw L`njxgN@xNAv*3Ko literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_circle_googblue_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_circle_googblue_24.png new file mode 100644 index 0000000000000000000000000000000000000000..7e08f610869ff1475a908cddd816f3ef73d7a68e GIT binary patch literal 1017 zcmV99a7*A=uoiUUgHN?1tE(&rB3v$IS zwzRH5_J%Zeu_uqBw~Hd}n0L;ekGJ^U!2gl>*qu3N>W5$cHWOqcSO5!PEPw?t7Qg}+ z3-BK;EMpzJIKmk&agDFy8kac35q7bTWwb27_)4_V!6`;?w=}{jI%uP`076XTG4?Tp zYuFHbSj2SB0SdfC4{ky(u!16|03|l@5iSq|Y@$p(z*F?$0@cHl6ay^a4O}E%V?LDt zFEE6Q%qKjLIlvwK3KzL;6tM-khqrKvIL2%&0UqETTw=~K7kYs2@BuDSAMh~L01qJJ zC+$7vLJM#Y@8B|Vj@eKG6nG1lnLjZTLV#CrncALofERF?`*BhM7BGa%+-EFIBETEC zMBQK?ZcGQh13XQ9{O>V^3T{koUja(=(;px8BJ@%E2(X#a_;n*}G##M8$IQmB6Jda& z$p9}?A73HDYEuEG(MxrF#Q;4_Hxb}5Z2a*oHW6Uo#vj|Bc7PIp+4y4{qSOq~w()Cg zYX<1p__b|m1~|3xYdg^j(89>ZuWf{uMu24-|C=po1X#E6zuB5bfL*v-+Q&^!|2xyfaGai|gCOksQ>5i%HGbTtB8DvYlXA+GU7Un9V^!uSdi;u>FEX$1JH zFup>BxW*S>0uBI)kk)+tm%Io?LR`4W5O-pFG_gu(eEmlg#UfmTsuac-kD7Ws{lb5Q z=*GWj#8eeSqdQG+GF+wck_cUKqt^bdi zdE)!1f&)17uh)|}D`Fm>;WGCL^WFo9=Wv;OHt7SKw&60>3FXMLW4O%x5yX*YVixCc zndstfXvbF0Wpr%i{ZJ2XeVBNJ_u(GgDlnJmkE1T`$8vc0ERGZVg?l%)@v?SoG4!Ad4esw%(K20mav8$9HNUpuJA=%p^q*Ov4b@%*>$$Y n0$2cJ0W5&A02aVlfYAH{#hao!`f`FU00000NkvXXu0mjfl-ASn literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_close_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_close_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..39641921925f090e33df2767a4ee5e6d5911194f GIT binary patch literal 436 zcmV;l0ZaagP)32ETvhYyB39D^lU%DgQgv&#U%8l^-CA%qY@2qA=!B5=cm zUgehujQG*l{{`@rPr!f|fEk^>KI9WteE@ilV6HEl&_rJ@p_zU*;T}RirIc{5NocNLm*7JGdV(AM zYYDFOvk5~8{Z*t_>U=!XvoehUSEh=adIga45oe)B9kGgT}7UT3Cirmr(oHPv^YQ1-p=Hlh5u;xggf zX{&yw+El-OrrKQJRl@b7x{HLmNkj95`a#LLnW{Veb2C+!`ppt#r)=g4@?c8RY{yJj~W@W|h^mU4q`i)2y~Rw@J`jIh$1%|In!~{Tb{nMqaxlgb+dq eA%qY@zJ@mriVM?qfwL0;0000dnc{ghQk!J&oZZ~rw*TK;>7NS%xppOgYfm&;m2q*E#g2FN zZ|&`}!z8?z=6qe8A!(o;#n#icjd5w|flF2ixiSg0j;%o37!*_)j=$$#9XHEFf??(F zL(3N35HbiK-zs%co{@!}b?j%LGh{te3*?%6r4m5=?y3DS=b z{9ydeh%E2$?`SypgQ-jvKNy0!9z0^^xh1sje!V0^r}&5UujVwwmAf9@SNe&`u4U2M zOAmLxT5^u}hsld&%kQz*S;+5tGryK!L7Cwn!yl%D8w{oAYX8dxneFN7=d#Wzp$Pz| CXMKAB literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_delete_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_delete_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..c582dc2a49d403490ae9efd4ae1f1e4f67593a72 GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%xcg)_A%&hEy=VJQ1{gQ z-V8K|Ao!kHcAx!>$?Vz#rL$tcGe*z5^h)#gi|O54tmL&%W#(Oep|(7EjnbUwn(;S- w&lMYmP1C(TbLaW=-RIAgZd3G}w50qy(}v#+>kk`GngFuP)78&qol`;+0N$8TLjV8( literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..eb4307aeb23f4d83fa3a18edaf288eb3ffd80ee4 GIT binary patch literal 376 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z-aI3;uunK>+KB3yh9EGEVbN~ zJ}sZZdfqVScLvBYHch`FZk~SNUW$ON_mow|r#I`Kf46WJ8$(^I-PPA?0vG$e+OlqL zzwEzQ>saHJ*H?wv)&0poyK%n!!*j>E-)wOSSC+s3H+9+X*wW{ZS*xbrNCQ&mjxrv9 zQ?utlgp5JT^Z$vB!G#ADt>yJEh_dHw`uve8+qX6SowD`+JMCN6PV5(t$h80cQ-AN( z6ZT;X_y4>&`PS3(yFd5eYhBwXW%6Rd+4H+!o?~WUc+mR6sX}p&KpcmDi})e#hfpri zmuMnTE+Yd&$VZR$r4{R+ds^(f{`m%Xg{}Xgch$E2dmC;8c{@Oi=*a;OPRhOf$_3`# w{~S`|ar>G6ga?&ET0elQV-I|0P$^(s_PG7}nu%?GK)V<`UHx3vIVCg!08!7atpET3 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_36.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..a53aeb1d339b7102b37c1884c79a9707dd284b20 GIT binary patch literal 754 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q1xWh(YZ)^zFzxhoaSW+od~@TV7n7sR@xuGg z<=1N#9`auBg=L~*>!R~P6+#=|ZQbNQDf}XP!L{a1uea|u*lql^{ojR}=Wm{WkQSNa z_F}&nSF4j^65EnBhI4LAGF<4({Qq*I*Rj6K^DU=+p3U!mMq}ri6wgObV?M4sB`CGR zyKn8BeVdDqJ5E(LxiG=_s;#AEa=?QQ{wq&?YHi!2-5Ztd0$lpM+jcxNf4tz}MEQ)i z>~62;zRk+^0Y07Cs-0I~z9@LYF7@E@jaNRU7N3}x{@Aj~Y9^n1-2zj)+%@O?+Li4m z99+Kms^!Z99d({1|FySWeRzWZOQ-+Jt0zl<>TMrfKJm&2#Bvqc5hf5l*K8@D`@i+a zwAY>0o(p8wEl^{d{%woa+?JSj<^OjI56}FSmp#`GXsP@exomYQE6ei>4o|Ev+IuV^ z`+Z@wZED|x#kG^gx%9MW2v=Gfa(lV<9d>xP{HU#bO`^pn#Z;F+%Ib+{x_I4L`(8NQ ze|yVNkjX%zIZ*$E6W6s1!7c_56}(SQsupLzAG`Zceiaj^$^-`p5or%({k_d%)O8UJ z-vshOnBUFt{ZWl)dnJ$V;a@!CyX%K_Oq?YWN4x!J1@fp(z`%Qq8haj14%}nV*pqZn z%&1FmH4|qF!op)3MqNEhi%$?qJ^IHYVqB##87BuO~ zaD;4VWp3oUR;Ung+lr56RrK*jhuYT`0xR-m*_pm-&Uavv^m=mwBzO+t7RB74v#A9lb33L~Or>mdKI;Vst0B;vpKL7v# literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..b47b3f8bdbfbd9b67d208988c6856b0bdc3faefa GIT binary patch literal 125 zcmeAS@N?(olHy`uVBq!ia0vp^2SAt+NHA0_4_pPLm`Z~Df*BafCZDwc^2|J4978G? z-(EH3Vo=~{yZEmDrTr|Ks8*)?(k?&BVv89(&rVa|u*|9yYmxqNcdyW|_=yTVj5%4K V{s}ble`^Gp>*?y}vd$@?2>?OkCyoFB literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_white_48.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_white_48.png new file mode 100644 index 0000000000000000000000000000000000000000..ea9f18ae63d133b7b3214e6f6e9addc7a1696884 GIT binary patch literal 124 zcmeAS@N?(olHy`uVBq!ia0vp^2SAt+NHA0_4_pPLm`Z~Df*BafCZDwc@=QHl978G? z-(EB1Vo=~=as2;3^QhawTN56ot!iG&EUDPAbM8g?mfiKNjtp{7%{4gU=KPz$7?Jhq VpTN51)2@Sz^>p=fS?83{1OP~PC}02p literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_grade_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_grade_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..7f38d09639c225bca897e39fddcc0d9718acc39f GIT binary patch literal 887 zcmV--1Bm>IP)a>KI{=!-o{> zRk%>gB*p$_vBHGil}xO$FZ2{IH3u zRLd3GHGiySoNBnl8kxa^{D5oUQzvs+%4u90Vu{S+Hu`bp6K<7x#OT3=J;Y=SolIfV zHC~imY#@g%6RekgtR#aCztA8zSk5#o5nD(>W;eKpbE?0OCe=f3>tz5*PO>%`pc*}EuMfx9$`G7p$-j^$k;^hph zRfI=5iy3wW@$6^irU*^>TqdRPq&#^1$Pq zr;={Dz?YQs2iu6t2jXleOF5s*K5pR(r3xHjsb+yY>7ziYzevh9nke-(YcvO}WrR|X z$u@RV>`z`Mp*bSKD@;)ARoTV~ZaT^`%@cQXjGI1{ZCv8IQP#;2n)#ONev@51#I(!2 zMp6cmWEVN6Js_KS0r;4EWC3aVfi1F$T|6O+XyJ85B9TZW5{X27`VZgg4^Pujtcd^s N002ovPDHLkV1lwKl$8Jg literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_group_white_36.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_group_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..dacf29932768748838090a2935cd13432599b096 GIT binary patch literal 809 zcmV+^1J?YBP)v6>-~B3&HQUfU$Yc^U=&Q#_&QMBSN;$&_ z-TR{G#}(YUOmAKLq6lI$o?1tsZhc|IaRP4~B1WgaFyeTOx9$-w-q!;`9LE=#1c>)_ zz-D~4M!c^c{qS8m-NgHgIUmX%D#b5bEi1$@t3Qiay z-dBZ#IAOb@zC14Cge*mUdA!02Hx>2ek&6>Pi}wYXFUTBXvdl@^T;|P zz5?{+3hrE@w|rk?j1b-6B+yrY1SWHU3%n$kTwZd4156^Jp8JMj7=~dOhG7_nK_D#{ z%51ii#d+@WhTjxZ%x~UskMm@)o!Jbfg}>7p1_|_~5KK=NlFCzx@Kg~`No4^&3ATK~ zIP(1J%Ojd0tmYi~_#>ZltY(P!15)u+BZVwlJwif~d9hnPr=yl*O27$~a4;|z&*Y&L*Z77xM+aQi(=;SDImJ95Z z>D!G%J)9XcQY002P%^#64?Qegsu1PKx(NRS{waY2Fv n2@)hokf0C%000000000SNkQ#7U34K=00000NkvXXu0mjf1VM3a literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_hd_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_hd_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..3f87b882eeac671c7921584117e1aa3ee7287fa3 GIT binary patch literal 348 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z^Lr$;uuoF`1Y2g-ysJH_m7ba zmALn^OC56TiQ#2Yy*ODy{Ft@E7nKsn`KQ&?%x3DnFn_l9e^J=}vrBSky?K8I2xe?v zy6D-Rt1>qV{9na=|2QMOZEfON*Z2c7^p(CGOtn8C9T@eU@l0p%;aIx|tsb^dnYEO@ z&gEaxdBsp(K!=fug+oBWp@9L&U}0ENHZ%S1?q`j)GaJgx-<)Psk@IHv@nT=HnStex zUqizp23cXC+6KqmdKI;Vst09eb28UO$Q literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_grey600_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..e968fa7d12c1e085b26c3f0501c3cd584fde60c0 GIT binary patch literal 856 zcmV-e1E>6nP)l~nq4gNwW>`&ex*9pKBzn~rUGtc-1^zc5~aqrRX3oyzL=oI>nCwu^A zI7bs*i$iv(FiDvLIdT*zGs(-m$=9^dM0dt?+JFktuh3+lS$a`K*UPhfL=zp+Kg_2I zSf(AhA#PGY{m&j@D{}K~^GaHPO2q5mWj)3M>|v9O2*P|CfSHIN&pt&|%u0M5@k5$+ z4Hykwx(yal30vmx(B=HNOF&QP##v_!<)Cqn(1B{?odH6Rt?wzJ95u|3=s@qf0!)Rz z{-Y>|Jr+uM+6AC1JQyFafHqo3rQ83<9#A!gsCWe| z8nb_D52zVKOnL=8Wz7DqJ>bL`qU;r59-_zg0CN*9cm)iY8>v0O+{kiX0bR!IEqj1A zQl1OUF95#@KmY;|fL)1S&`baV5P$##AOHafKmY;|fB*y_fKCA}GX-ec1CBBUsM`ZR z%M_q$54fHwz?wav%vELpEr#p?iVrgb*h9qu3~`O z7dO>q0~X0HI=XSA*s6f7Q*JRXagwPL^m%mQ$UW1JsrNK>TN@HGoi0r3I_A(-^kLbR zN4)}$&gv^xW+tzdos#7tpr18)SteU?n@wHg)^iK8-|zkQtoGmi2j!nPVCsonIqP0e|>Aupo%LgUXG`32fyKwHb zPLFi}Z}kiH!}Ym+?sC(JJ?E$(+7NJ6X20T%K}EqWwmLR<&r(lI}vUw<_JSjJswRPq`+b z`~UN~iajS?y?6hINvQX!(E1S1Ul#E$G*JY9X8EjLY?mfkE)VfhzEuiVK zi1ukln<@O>7ybH@WS1)0Eb!|pom#3P|J`JN(3<8%#n{V31-fU% zpHwo59-61)F(o}Yz`=7};yW|{g-*As)C|jKvL0l3dpxEscZEQ>yIApiR>qLSBF~}% z74yxXsYSlC572*B709R4yYu`XwkTJ=;BZe%#w`=>8%%wuSl@VQ#;HwwPfyHKY+tEd z$Fx?ZdnL0*`?b!MJl}t^U+G+#XtTUwmBi7I-SG~Zd5NnSpWcW&enrBwz9GuMw4tcr zx#8C~dk1xc(B~=_yl4D6$G<@8(+g=Q%U$y?PEVd$yTEovR-ssi`m%f5_^opSM|Jc)&+ClLvk0gd~{3YGFX?%ZDqgGvG4T?jvR^FuiqNJEqouL z(y-6%{_bxLRTr*{aW43N@%u{K1$JLd-I+4ff9>1IUcy*ATZwUtXs!J%W+}(`T$Khn z_xtkS8q_X?%W^KLzG$AupCMKor_!+Mf_W~#M*lt+l?JVg(>JrHc)6yuv3N8<(42V; zoD(3ZbxqSPFQ_nFo&ZBb&S7Q*)7hKMQr)T-c&irmCRfs@sxeS z@tqM2b5&pRPk1D^&PDEp(N&FX2dPDk9?WyEeu!WVs;Ci)TyR*W`DgBt;+RgE3#y-= zZsK3!apB0z4u-SEU2Z}e_KjbvCxl(%`D9*vj`3_^v*V>Vm+FfnnI>^I!hH*5_#k^$ j&4Eb;gf=ov`pfNLqCNM}=ZRl{OIQbHD%W zOuD0tZJA6algVT0>V@V9RKBR+{L?Q`q(p zRZ0izF&Y;-o##1( z0V;w49Lfu{Q%EN#$Q>@AkU3n#kO&Xo>zGS^InH$V>F2kUE2&mQ)Nl>W1rkn>eH?&K zKF_m?VxpFp$fuJ%>_2&y64uHYN{Dl4BWw|?+kNhjB5Vp9$^tfF8ezXsC0lrkus^7k zCDb#Du!rnj8p8fyxGZ7>qX^qc$x+D!f~HU_%cy5ML8B;FQd~<=D;vrIHldB6OO*^m zSVYhna)fgUn#TYo!7T(muafXTDjBa3biLxEnt7O(u!_@wdYUoKqEc~jDnVCDwgXID zN6-n1i!U(ErrLQxKjvZjSn<$E(6y3_024Q0%CU;#;4)0@3`r$m7#)}{P#nA)e*U-$ zF!2(mHxwP^v|>6WwSdDhHPcs7u_dNX`ll8!2p`ktii)!_eJQyNF!62T)1QYh-I;2@ zJ(%uSRJ?)d)Kmk`!1Su3;#W-Dr5dm!rk@lQvoO`A8qk1gx}u^L(~wjHhGA+}RQQ<6 zQw^xV)TKi3NWx1$z-EG{g3Mti;Gs#ZEO^SgsE@d%6K94X&d2j@#rSw(l@GQ+Yup&ecH^%g(~3TfwA4rhRhU@%AU3Y`?v!Lf3SU0Fae9elyvoW!=& z(vLn=FpLIv$b1$c{34N5wWHOmdCX-3%FC{OU%;if}-T(jq07*qoM6N<$ Ef>mlWoB#j- literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_image_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_image_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..2ffdb55f264ecd3610f90890f8202f93c00f72e1 GIT binary patch literal 570 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z{Ke3;uuoF`1aP>Ea5IfQowI9-hvuwR$tP^fy(>8sSO2|8{wRtGpvc@#B$n~B~Rwm&yIIB)&jy;7gW zTKL?7mzK@v|L<(N|7b3=;GHmT*|XKxR_ zisKEuaTo73N#D@a7GnOhx@e+huI&M-u%#?A#q8EMMfY92V!WoXj#HDtTEZ^x>C~Zf8IWQby>8Ib0dT5wN0yQ*dG`x>m;y#Wc*hW`8x0OY*zD)2SPUjd28<` z%OxHB?A^isVY&9DKSD{2WgAXtCo%nb*|kec?7;kW6+k(LjH+Fa;+@JJK3|^tKXA;DPbB};p_0dfAo z$vAy9#+6S9#ELYJ@(Lqa#%C_802gIqArYp#f(wN zJ5D-2x}I^0EQMtFA?SeRyu{vHx_o|^)~`kO7MeJbsRD=Aw#N4d<{5Bs2vT z(7+gW9I~nSN2#E6lJC{kK0$L^4urow?@d3Y+FGmL|;O)mE-^F4Bc9HL2 zQm7ENoloT3SxmqprfnYoS5!#bXp=BSqyK>0=yIe`A#Mj2x&gld?d0n~g}ejgYx5J3 z2Egy^UyUJ3s{D( z);XXRX&hy6FOb$b2OLD|GaAs3)ae{>38~9yz)_?g=YYFNn~esfkZw5#3?r>T`I=7o z+A5@n&H)oh4MqdzBfWAC_=prY8jwJmaSq5K#f%2TkiLBX0pHn2D2X)lKlmdaMq2s3 zeU08h+F~>yg>=(7pcm8C~mULv(P2h^i$HWskl&kK!W z1ZkhKfKETJl!_jtL1O{;k-FUlY(=tYHWIKD-3E67NoJ5v83{OpG)>%HfT9m6OI73n zbC^cDf^r+M9^H}115Tj(#eF~-qezp~L>f@f6jFv+?gJDZ=*~qN(2H(2%1b~cZ;&k3 zL>90X-2_Q*0g5hkkEx6#pqf#1X_VK11mozgMH0}DZj8A107V=5_M<}HVe)PBd(>b6 zoyB%ki2Dr--3^rAfQ4kyePSajq;2Lix=9xJ4^Xs&O~Q_l{`EhTudUbvPZ!B&aUg`x zzD2%ssA2=k8N$vrDp3KgnttpIGQ0QyMI9OJJZ23lfURW|J0sKtb?mZ<=h(66p%zud z>bZoyXEX+R@O5c{1jurnYLt)7;RI9Id&-iaj~+Mi1PVr+=0}fjTW6S}kP#ZgIQ(7D z5MMJynq@Bjr=gSke9a&=VI99OrxzzL=;tUYRxzIhF=8Z{&ni+J<2o;Ka+cZQUVzxi z6k(a9Es85BjSLWm8!U+K5>OlC1Zk9QQD4JKaDdkYVS+SqGZ*11*vk`&kzqGU(^nB& zxXOFHn&t{WGwWNq44PmQXZZ&=hUsR5_|TXQ5UXPyo%C>vhrD8jFMMH!S3Kk<=SkB- pEh@+d`@wmo}Oh<+N15WEs9gz z&*;y%eL%L?%QR1N8WWq`iW|y@jSldJTI(^!Tv!p6e4RZeaOZ2g2c4&EzccEGo<^Xut4&ID_hU2hRIe5>v=PBwlcCiNfw-U6Te`wL2(+xD$}B*^V1aS zm?pS1)=E!kF;d`6br3q$pfZKgQ-gU@0GrA}9uFr;tP;E(^(-LA@EAN0=4hF{diVAC R=fLn{@O1TaS?83{1OS8@b+7;c literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_black_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_black_24.png new file mode 100644 index 0000000000000000000000000000000000000000..90d0606a4590ef538301e37f1a0d0490cca327e7 GIT binary patch literal 832 zcmV-G1Hb%a|nR(nD$XsI1Bs0T3aKFFx49^EHb73?!H8nLg4WS9I zTd-u!nnmYK*{zs%`%p*ptmBM370?kYVuLMvO3iykY_j7<+>2(kPwi+A}F1pbb`_eN+&3tpbWyp z8xoXGP&z^B1f>&{PEa~QiG%|Zfzk=;M!4Q5p>`!eCZXPd48q7;)lU0SwQE8?VZUk@ zL|VtdyDHKys`k6+i%{*NNV{f`Rla^j^`KA1wg@f%inQMhyz@eualIWE+ain$X}&P< zP6}xr*V|6*Z4nL%Y2G&QjtXhsRPBAS4Z>SOnr95WJwlpaRom(BEfZS)5YpUjz*T=| z9#ZX)?iL9LgfzbxO4CA`PgLWW*b?DEt0L_UL+Ku|ZuhFjVauYr{Qp#S?J=Ylgfw3p zQ;l6t>uiJYnV~f)*6o;$nlNR-Wo;cxF7!p%FE#Af*_!)pRtsZJWfML&)b{nfuKu)F zPWgl}LvC8E+v30pL+)ljh;_SavMj<~u84JOn|4b{ga_OZJ^R_CB@rI05`=F&>84E{ zz(ZE+LRb~mxnj-}cIfR^2hICS2vHBheJ+a)x8y4yIc45yU%DjHYDC!SyvSc231eRN zPuT>qw{oN+VPNMG*1<`Giscw9M6sPyv)ir~t|#bUjCLfJEqemNEgf%>Li`O-)TrO-)TrP5%M7+Xys|z?EVE0000< KMNUMnLSTX;#)AU@ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_white_36.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..b0a10fbf67a8ded874cae95f4c17c937b364efd7 GIT binary patch literal 1326 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q1xWh(YZ)^zuzdA&aSW+oe0wK0V_K@r@sI!G zKB=A%OVM{?H=SzrBE?j7^P-@{c}v(IdN_5gc&M_X&&Q*A(h{ppGp&r8E?BML(D8h` zKwxXG-`P{D-;&&17ru7YoImgF?T38pe&70R^ZV_yUFC0o{W~}R;PW(_-TdFSpN!O+ z>a{dzWeA9x;j3qj6XxZ!Oum#>O!E+f-tt@tr_A~AHp;i{ORml$nNgM_|(6I&-RC{NWecA)h`c% z0vk&feO$G`!Rq3-9YChlw&VOugk3qF2>o3se3W~MaBjD}hkBPB5|;5$za?cq!B4~% zjt%oe7JU}&h{LK@2u*Fg(yK0XGo?J#jdnd^ztp)1h?7`~I!;*yo^d$FD$o%(SI5CB z@Cgu~0lLwJX_w2*NbP5LD=&23=%~EjbvwXfL4Cn)`OoioR=9|kndgZgX8hZB+vv=0 z<^a<`ZnHMqhTH2OHuydIrtvJ+{E5$%#@n3*4!;YlB|qnhKJnSYx!v|*!>+>L9G~;V zoGpdl9?SK%SfE~L-Tm{p`ULHZ=Xb2-WG|7AJbQFcG@qrA>Ex@23LL@>LLLjReq7P# zvbs>)&{k%`#s1sv694Wp?-YD{^sR!JP=;_`YFgrt?Uw3`UTZwwrl@lvHsvc%TYa$Q z9PW!zo3c2$L(c2(_y`q0TW-JnkpFr8gsYDuSQp97UC~uP`KEx}3$abV zRz6xfEi>oz+!bed85`%=|I4Z`>y|t*^+oL(4u{;7&_`iEPt5izaW`z}vD@@2+3Tvh zw$;s}hHRR~XB3WC&fcH8=x;<|!?X#p=3$>-8So@8^fB3Q;c!fD(`ymCVCAgiT`VT; z^(R-I>2h!h(@{v4t>};wvHR-RxFW%!_sfL4^=qbe{NwUW>A64ar*M3%Nt+rMe~M1J zM11=U=~)^!6E@1#i&rL{*ggcSYis*i7u~`E%V# zzcNIqgNrrg%EqqEJ?ZKZUfRt}fe8xb!I6h09o}=_T6x@{7wF{OZnu7hEYSSS*u8P$ zOP7a@cg{Yv+_z*~o8^( Xx!o}wmJa`bE1y85}Sb4q9e0NX2ISO5S3 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_network_wifi_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_network_wifi_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..eb284e3838ab78a7be6a1e1007894dfc8978985d GIT binary patch literal 1043 zcmV+u1nm2XP)V2*MS;BO+RaRAPy` z;l>iXAQ56MrD1d)H=VXRr!!~y&L-!1ujf0@n>p|KwpWr|TwGjSTwGjSbVCxEWHXcz zjAasq6jMTwGD4IQq=X_SGmZd0vdJXHF50Ph@l!wvA(b(ciTLr7W{r3X*^H)GwYFRo zGn#Bt%~H=GmnlNTJH}LU$uLsA2R^15qTW6V@d+?aGS`t{S$tLuM-}IP--jrwyAG0 zo<#atCVVLM%@vuQ%XcGSYx!v8(@jplpP+?-88Mx{9VaTkW8|Ze*IEyxGTCwZAwo=Q z`MA=Hpd%9qwl4h`=*R@T?W@3nHPCVTDsYtk_?Rh;WTxvJw4AkU;RLnR^Mv;_&_pxM zG||9&9#c;($Jxvp%5^@eh$Q*FmbPM^&3dZ2OCw5YZWBfXzo};{6$+o6n`kXMA>j~9sOA%*`N&BYX((Qq z1FE7p1FYr(zc7kl)UYz{hCfN!!HIk^FXy75mnI%zYFH}!{8D-<-H{E5`SDz;X~Ha; zILVwChyH3dmBaq|>1N(xHgDOeqIhMBd3@`qvJR`b!h#lyaavBB3kgxh2dv}+>j+UO zy9Y~{LOREYU^UGgRb0F=DXhhMBCOGKHh0AG1P<#vTdHT$m`Z~Df*BafCZDwc^29w|978G? plNp)=Km51n;8#DVkv_$ki-GCDeZ`wzAGd%sdb;|#taD0e0szsl7@+_F literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_36.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..3ea7e03e5dc315fcca0178a146ad2eb1b013c15a GIT binary patch literal 110 zcmeAS@N?(olHy`uVBq!ia0vp^6F`^|NHCnYy)O!+m`Z~Df*BafCZDwc^3*+D978G? wlNIE9ngS2}|Nozzqcc7u1OYp847l7F8Cs>jNuFVdQ&MBb@0ISd)(EtDd literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_people_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_people_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..f52bd1ae594034b9b2b57186bea1f86b820900ab GIT binary patch literal 539 zcmV+$0_6RPP)Hbf&b+$|);-HEVtNN_Ur32^DRzE!~?jjsz)wN0J0%iynIh?<{=@RIrza zSUqGf6$NKZr{B;QMjZ!e!<9A;P*-5mE?b`mqd7_!u61#g(Rt@xH1*k-$YbL2n2C8N zmh;xo|B4;-5T_n?VvaSD!I^N;S+w5-&TW$SE z?8T=&S<@%k`j5DaPj|DX*W3D!=*6ertmz|c{YQ9aov#xx& zv77cFm{hZsJl>@#o0(01Q}{jKH!vTV-7(`x(=<)fG)>bqjXZ0FG&m+9;fMwyW%3yN z8OF5*b~xdzy1Zk~Z@?9*oN`_XFA01F%(G9LS`>W*EYT)yF(uys^RyYJn4(XBtL!su zEdqZ4Rcu=K1+c&=HYF7O0PJ8}=mX$7C)m~@Cl6S|rPb^J|CJgL;!;f>(7>g-Jm46Y zVtGJfE-6R4u?4YBE~m>VU|78)MN(ZBft>wf`s$x@tkRl zJYevOgmgHo4sV#nV1xlFmSdF~bz*w-h^bR!Wx%T|@Q{g20SZun0u8 zazIR%zrY{bd}fyqJmmo;ru+lkpu!fPNJvvclWi&#<30Nj#)J5DM4Ip5fKI3VNAZtK@2IH(r zAxl7kFO0jd+{_A)=KzT!^4S1hBUP9M;5L1v>T|~(uz_To?tncci`)S}k?glSKsp5o wrT_&fKmqbofb$ff00k&O0SZun0u-Qtf5+dLUy%KR+5i9m07*qoM6N<$f-g-0j{pDw literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..33d40d8b6246e4f62c3791c4ea59525ec5f2191c GIT binary patch literal 577 zcmV-H0>1r;P)w9!$}%c!FwLkWa*wJ_*~csf`y6m%W-=R_a% zAV{q}hM(Sm$@cuV-9O>JF3CCPoO8}O=Q@Zy3sk6aNJ`29H7d-L*JZ#2>zr_&W8O2S zm~o9IPPs_RD{_hx<80H4EsBZ{)9ll#gek>^arS9PLQ(PHI@`2si=1M?5?L%N4oq-L z7AZx=fOWE}$R0O1A*&;XWsL5V8X>B(#vvgRStBJxQ`Sfc(Udg~2$9Gd zH9}Nnjdz47%Np~9n3Xk#IVP)L49Ol9vMMVEjFFN>lM%&%MY4FVSde3jcGVeFJSdXT zj$LjmE=;jUt9F@Gd>CbuR@50$oXGK#l#4WZ!JuMBkqSqg=ZLqA>M~%MIm%Q?XwoF1 zN|{-PDqnPNb(;U*9;~*OrbEQP#9Avj42ex6bfSsg)xP~n4ELYIp>^n?mzwkRjRfAM~5(h P00000NkvXXu0mjfo}m0j literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_library_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_library_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..8627f4276787a7a84ff723d84e3951d983c2b4c5 GIT binary patch literal 553 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7!1%$_#WAFU@$I#T%(FIWj}_aJkM8^Y>`CkA z`fUrpu)lAdc%xLT`)HCO--?|JRKG_}>scva{m|-d;jyyofyOVmHyn4jF$;E5dcd>3 z_cw#ggYA7Tlvdt6K1Y7RdVA-pGnI_Lei@f|%$7HB zF*184f8o(iHQ5bEia(bekT@^9oLS3i&$W*#vIEa5IfQowI9-hvuwR$tP^fy(>8sSO2|8{wRtGpvc@#B$n~B~Rwm&yIIB)&jy;7gW zTKL?7mzK@v|L<(N|7b3=;GHmT*|XKxR_ zisKEuaTo73N#D@a7GnOhx@e+huI&M-u%#?A#q8EMMfY92V!WoXj#HDtTEZ^x>C~Zf8IWQby>8Ib0dT5wN0yQ*dG`x>m;y#Wc*hW`8x0OY*zD)2SPUjd28<` z%OxHB?A^isVY&9DKSD{2WgAXtCo%nb*|kec?7;kW6+k(LjH+Fa;+@JJK3|^tKCHv1STzVC9adTs@QpXDS4X%nB^W3tnZ`ySIQ@Hr>P|%Evb3!hx zzwfywO3LDCPj)!Fr0?51<-3c|*Y@9^`MS!!x%Ob)`|~X`(ZS6HH_mc~MLg!RRog2! zJuA-3&R9n##Jv_m6CNCPra{IDmJ~vG^M`E_1vox7LE1u zZ+cJI-^TFQw6Z<$tMz%I=m_tI{lDhSee=L(@k`$%@6{K@7X05n>-UegN3~~oHXgnD zlB1ye@R7H+Cqlcv+CS^eU88tF=;HR}J0o9wscO3MEb21v2gP#1FYiU$-n%B-akshAlUq%dr2Wgkgg9k121<8!eMgm@X4en0Vrb&HYV#*KO+8*l_I& zqe8N82(m7C9>c%OHkirY4+w=Q4>v!7dks_K+@`Km;SRimKl z>HEZW6GOWteoCEW60z9(seA@6+gH_M7tU;7y#q>ySK_qmszmEKFR^C`IltfQyZriR zmrS7D{6M=+k9@yy+ht|83ipKiD$yJB_Pt;D`HX<-`l&h&|6YbBl-4mm_V|NGW>p-IQ#Xc^->KFOt$Tu>=MdQT+{k@GxwV{dvcGrB z-}DaQ6p(qP{Nen6jzCj~4F_C#^fpYFV0SP$ty$$$9P77fvWB=qJ@=Y|TCel#HosBs z(v>(`R@jpo7P`8R zg{90Lt0f&`?lL^eViO2AZ`iSm@yJ!6R31a2DNst&xD8@?udTeN#I8%r_sg2!eom$?*X_%R&Z!t~|1-cBYK4gm#+1_nk5gW={^?qALV VOCpPJ@c;vi!PC{xWt~$(69D@(h;je` literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_18.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_18.png new file mode 100644 index 0000000000000000000000000000000000000000..aed7668042f3e0e5843335384e0e0fb6c074cf96 GIT binary patch literal 340 zcmV-a0jvIrP)XpRjji30$wDk+(xOH$$Jk<>UkBvlRobV($2P8!LC6HhYZJV}Ki zCz!J#$=*&BNJ5f+tVqy&lJxFGgMfY>2www%Ac6=Yh#-Op`jq_baREvQK?L~(-EcsO z5=RUkKvyiL$tA|$gZ9Df*#gvv&Mbr3t*q*s2g=b34&4N^JCo*7L^=hNwNVi&APrbe zQ)}GKdRYN!#03>9)P|fFsWbT-#<$icq_h%Uos{0`tCAY6rn+;)Q6n|l+m6l=$KiU) m;R4U$iqqi|m|+;^AMyaLjQyY#Q(tTV0000lF!{5tp%KCR5mb?pa}Xe_t<+1tRn1%GSIm*qt2q37gnYd+^im z!Jmkx=hg>52XoGQ&vM>hwPK&Jjr~-h#D_m2U;snb z|CtyB*uG!C@S6oZWAI{offq?t-rm z?)?mB=2MQAyA!=ns(`2E>tb>93-zDU7zAY+e)|1*YVS1ZeM|9w)oC^AZ=RiRwqHD9 zJ^5CapkZaHStIEWkYd`DhwNF?9=H^3*eUt3>zeBh`m~+Z~ du-C80GH;aY>aaP-rT`2>22WQ%mvv4FO#r9@p49*V literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_36.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..1912789d2fee25431973e5ce6b4e602861d4a00a GIT binary patch literal 531 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q1xWh(YZ)^zFy8WXaSW+oe0%qJ=xj!T)<7+V zVD2kQUWG4QayZsbSjo2jxaIBqrS5y;nTyX&{Ws^@JikdQo*-m$yV!i~yEN(Z!RlHc z6u4|UnD`eRXx8|waLT5`h=0);T+B}jT{ay`{EJRBYk-+jHrfAI`d@kelKE@rFPqv0 zc7gMk^IuVa_4!NVFPGYRb^-HOoc~6fJv>iWyBzkStU*5$%p_^GZxeOp-KW%XP6OkXR1xpY5My7v5~u&#WK zYHjetpKc|gH_p5_Gye>9^+nHe_l@T-t5@B&z4GGomrlP!2eW1_zmOAl&GmGoh=2K= zGii;B{HMGIN_}8i^tzHSR$b0zB75KyN0CZ_SX&E!g-t zvYE+oKHp{gXNg!fB=stC@zUMkP*p#w42~TYPkF{utt`7-O}`oeBb&j~)z4*}Q$iB} DyW-!8 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_schedule_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_schedule_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..19390a8bd2da8b506fb74b22ef4579001c3b76bf GIT binary patch literal 1157 zcmV;01bX|4P)CjW(JX&nc;qEy(d_~oX&9H zzR+Kvxy4xt1OkCTKo2e4!Rt(BHNTN#J4ZOecC!4+Dkkw7x6>piBceRO1b)TA#^Gni zaxY;yInbV4n9p7+wToHYKs)ghVO}LmEmFKl$giS#n~i8#PlAZl7Y~v}Q<{6FUbu?o zcwq@wi1&Dm-FRgu4}1O5PQ_*m3m8U>R<5Rr&UB`Ut7#?1Fcz={n~9!%)HL%orF=(% z{-p;-+R>i`-%-jJG>Sg1;4g~V!zlVl1?a;l_E604Tqe5c%{mI(!C)Gs3N$d79Tc{P z9=iX2;h*m?hvpjBPIGZ6B*$fXwO_b+{^MFvz_p|b7m~`iK&Z&4`vK>Q63*j83i+JQ zQY)sA&mk$wNaB!hV(rsbz9T#>9w5dM@;y@9qG2~~N4Q5k!aW?pZ5LNbwOEFm!_(p+ zVmP=hmFjRm`I6!>lH|KjDo2D2ZXZb5IDu4zk8sNnkxG%k?LW?~OMvr8;r3SLqyGj> z4%dok1hC^;98Bv8NhNq0x49x(0qmHE+e=bD+L6YzgXX#hXkjO&H0`8Z+=Sa;5zPR0 z48iS2DHn4v?V+LW0UFthX?FPo=pIa?M6?6gF&fkEG6z%c!>x}m0s2-sp)n5AcOqT{ zu;Y77W2GGYf+^u!fCQ$W#g1kiO#OWeFaVQ7v)FJurY*GdEkHZAV!BOicpcLM5w8N+ zu>jL+V#8!i!+Z@e9MdGRVKt_huL0tiR*4P2VQTd?KpUoC#fB`Vt9=d71ye?B*p8{m z*8t6!wuuc#Fm?7dKnT;}Q$Bz%CB$;N>XncWA2D!<5k$TJh_#1NQ;tXVhEeY)vU^F9 zZxy}uCo;9Ago!XiIEdR3Msbe*QbKbvXV&mC@@*ilznD{8PMf%oH2FSZp#E~&zM;`9 zrejQ^L48AG-%_d;(-xkko$8j-zNuF)rf+D~-PGHURkVxAVUp&tN`&3^gDvG^8eG=F zR#^XNQKy*xA*6V;Xg}OlFQ(fR4tK4`>n);=E-VM$RX<+0UvQ`v)5Yo+9QG?FbqZHZ z_DjAL=ZQYWOFsKG>xWVYe1uz?$fBjYi_%oXK%YyKrhx(*iMGfP~~0x5Oz{njvo50$A41H9!6K( zdOVuF_SR!nH1QRsd{2S_*5>a4B>3Lm{Ot)sOu=R=3m8tEHoDMEh!D+mp^Z4hS-@6o zCeS%}0AXEVEW-v X#(7K4#=sO`00000NkvXXu0mjfg%~3Y literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_search_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_search_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..dd5adfc7f990333743a5f3b34f09098c1377a4a4 GIT binary patch literal 915 zcmV;E18n?>P)jEh5hl3oKJ*oh`Ol zr^+oB7$T?k#zD^UoR4|N90j!>Iyk`!J9UraYA5vbfM(sNPwjv%=Bd+)Iv42D?jpzU zgz<>1b`M8+O;{V0v^)5kO`=faE5(naY|_YI%ri)VZaV3tn*xJeVwFZ}e5rVm<25b; zS2&~wILuW7TsFumK77U>xZGf`K7kxJad}8aabceA-f~(y#CO!#?!4kbKXq&`=v5Oa z@)BE}gYu6K9$9%}f0n;T#fJID;@`WKxs|t+{9%CxY z7joDRD=+fxQFdqwTLs= z?#MTeW2;eA3+U$^wqx>-``BKRQl7eyEDoP5*aH}XO7{#TcAxz#FcxBC-HLlSgcgC@@I@#yG;l$O3#1YIz)iDGG%q57`=7 zzz<3nC_!EB>!6tCca)&E1Q7@q6f^uCC8%XF1qw|b^ifbWsKzLVSr}Bn56TxPG64U}upo0&*;v!2U z3wS}%Ylb<==QKBX%orc} zduF)9`g#&t%P!7xi>ExVn9xhkv!vcNuFeqqS3Sh@!jsZ=xL%(B3Pp0dhX z-}~8iZ8}x7Ytw3rb>8!WW(!>8gvbX|%(L8Tt*W)tr*fOTz|BoEzye!(!h`TZ_e}N3skx-zO^SrDC=DhC~uf&}^G5v}!gXYN5%q_RG?K zPiu;S&}4-UdC*~nsZkB%J*i!u9I)K+(H{o8+irQZ%Ob}_@65JIo^3QMdSZ;{3 zoUKhB?R7@g|C@k_K<9 zr#Cf3vW&J_y=-)BB+se#sE1uZ$~V%o!N^FT zlkJj*9i~NnxI&ktb($OX<9dwfP*VN*b$eIz>8>lY~kL+o(!$ACDO5}q}b*ff}*^wXaQms28U%aXsFGb!M z?o0i(&alWIQ*F~9txk-5a)}OoX?J1dmqq$=TjZOU^=3unonb!LlQo7${+X=R(fnpo z6oZR(I9$66qBz{{aJNLUcu{xHMbQ{)t$%!GNEDAres|EXCPp!trQHGNM{&8;!YGwW erBbQ%zx6lP^mn*)r_FBwOXHtF>f zBs!87v570$b*Z#?gw0$KsUoo{K*W*d`rbgbP9D2vmk+Eg@d}f=pD-SA@tvmhaofkH z_^`Z1p_gqhFW=Sr|MvX-UHvoHy-GaSsifE<;KYGMxXit9l%spi#-n!Wb2gqA%hoYE z<9xX^`O%`)FB2x^|M+o=<*i#)1C#cmb}n_5hb^qTe7}f<3Z6ZqHl_Hep|OeN3(ZAJ zY(E@zb1vjBSf0^UaZYe+(E(#-Ti2i?)_N=2i`{s?h`0*AKhYEj6bm@=*~;EFJjNhp zfqK3x&y|mFcK*|OWqx7ua-~_>HalZ#mS1%6uj`tjn!U{T%ag?&^HyCyH2;jD2fyx? z4;_xrZmtU|beY~c&qgHhW8QOd{fr%9mk)TC?J1S-`O*^R(*FJP<|DG{Ph;&W8h*T^IjDi+bW7y)?JA33fcc=O}zOPVK2ehdFkipx^U*cu@cgIX>vu_ zO;GvVQSVOUw##WLOVnGG#OAVBJ3s1SdtMo4crAH-hw1T6#VdnO^-T#aw!PMMqe#bU zhSt-K%BjW;a?!4Dtf#&4oO9ty~E&D~&|5mN=UieajL(OKZ{OWgS%@a~}?(Dr; zFoWamJw?saTPpX(XwN&P{I0!btAULBW7!g>-8}aV(w0vQ|MTtI)WsWa@R}@|{aDM> zdP=2_{@N{=h>(%A! ziukrao6?mu`Ayle$mf@elWNm+UTA0bb|qc@DI?b@W|1lEA>te>^aVbg+|K?WVv_;GV&QeU zx3@vi+C#Ut<-We@7GasaI^XC;{WtC1yZm0SI>eH7HY2p!>b$Jnmo?_Ki`o^Vwn{GB zuD|!WsQ<3JFTZVQv+Na>Tkwfx*@n(yn+L(VmtH>(Tz>0-i6f(ydjj9?9S6m`Li4{{ z-`Vq#(aUGS!Kl0o{wrTS<9aP+ZRF6&aV7e2DVwIduiU1khRsYO^AAi~XBenHiP{uh_UY-*rWM?o}2B4@HCaaFo=EO;067X|?4o+bZq6`7_@AXa2Bpvd+b; z2Pd$~ymfus6>7dY)cyc_pLzMhj+rOQ=3QGT@pW^;S0q@4ltEr2oIu)!~x>|6- z?!`Vq8iiRo53VW+=mf+v#NQ69U6>Pj^6{=P`OP8R4)wn?b*9*QmlV$WpdEaSUE-^_SeC@lw zs`#x4?}Dp!tukqe@k)Eux?PxFB%XBgGoI)^A@~_}XfR;umQdI#eua&J!`WcDT#&T}gM&hoCC`Lw8JpP| zI9xWY5WG}n!{DIN6l&s~y_SJtA&1%YYwoX@7+RDpyrZgF89H1RoSPiP{eQ&;+rZF@muyAKi-fIgqLfInp+r9v4 z1_iOk!Y`Bd_AZUlal<6{u$b?Dumvi5EWBf}xVH44@3K*xA|n6su9dqq=jGM!;i8Sukxla eF=J$5h`^q$F$*WeJ10eIg7}`UelF{r5}E)flCsPI literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..bf37b57f9c97e150142064fa0b6eabe4126bb44a GIT binary patch literal 495 zcmV9 z5#;%`0TBdwetkeNL7qPcAdn!>p9c^|SjK+rl>|h;RP_LWE)QWoKqkVRfGmW00e-?$ z`u{>bKr&%|Kq5f{Ac>#@kU-D^h$iR(L=rRsq6oSG5d>|3V1hnCAVDJ_h@cbTCp`KH zS^<*@dI1v&ngKvRPS6dQK+p~tCFlo?5G(*hf(?K`umZSC2nU>W5yAmmKocPxu)y9v zVS{7wsR#UcFShlzEpNOMG+ru*D zcP*wL`Mg;84mm2!X>isk7Zh7p+Q!Vq0cw!UnDb(_c!0fs&H@#n>K6{29XU218}9)1s4`dr^_*fT0_vH< z^aQ9!ll=tHl3<|;KuebED2M|s$#jr&3E##)jcv*c#vtK zyCP`UVb5V0ZEIb8YT%{Wt=i$h1h}=m#++}N~<_EI0IvW z_Gd8{sjuQcF>{5RLii%9Mw!km)*|Iq;wL&+q$!9m+SPchbKe#|li4fk7R+?fWjL#p z#hk$wsO@kmN(dBmC7gPC@)i?pNz2{0=$fGUotLAT;zPWJ?)41Ly@`J3zrv|)PIdl|Ft5X z@!g^mpjfQzsB;EVz!(i=b(ya)%l*sR#f*#OtNQ)z1#OyL>>pP8mMpRV|50a4zb9D4 nyP~Zlue5;~l7fKb($|uXYV3P?D&}zlQz?U|tDnm{r-UW|VX_$a literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_18.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_18.png new file mode 100644 index 0000000000000000000000000000000000000000..44c28e2f2830f927973beaa3a143ddfe439f20ed GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawHhQ`^hEy=Vyh zQBv~(_A|Uaeg>M$g-&EJ3;(E>F0WfsuqEq@i4qW8@}AzdO6rx>m9XRe^SrNqJ^A{6 z_JW14-f=$P%=XJsxKGL9nM=c&PKKGnj7I8ADSj*`=EzL26jUe%O0+bb;bi0#P;hAY zVbJ!!)MTL9?7s4sjZ z`dg=nZ3NGX*QczyQwj`vc|$kX%>MU4_u27-XQ1Fsx=&8bpK^6=W#{+5{x0v--*iiI zK6_5eHWRkq-woYo`i}j$!>)2&V!wgH0wW@j83QAeoL2*oWZ@_>deZ&>ak+XyvA!1j^LK3P nm_Pheb$}Qopa5qqD6eI%v1Ev>S}gk$=xGK|S3j3^P6rjA1>qVQZ zeG4xsc0J;dnJ?aTX`{!ze|(A0FE|LDi((e|<}P5UF3ASe3;_+SSJUUd4oqHqHsZV0 z)x4KB_rFGGe_Qo;Q~3E^pF=`zUnlQ$cz&xX`SGgLHH~t!IZCom2b;z(C=_nIms|Oa zXNzENB?}i}w2ObrrxH1h=P#`;OtFz=pEYgyZHM5`B~lqx^YoavK6z;n5Is+hd8z{w zr^*Cu#QvD{-AaEl<=JsK9szdie?sim4x;SVP2%j;XS=7R`zw+`>(a8*SGR@$JxTdj)CFqKZetNH~DV| RtUL@7^mO%eS?83{1OPT0pql^y literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_voicemail_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_voicemail_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..820ff5066b5118de9972bed7a063b7da807d4ca6 GIT binary patch literal 971 zcmV;+12p`JP)6o)THAmL%DbSg-+^g(O{HJX4RL_<^}g^#}h5~#E=EJ$c7TXYQ?2hjrdRhT*U2@ekw+`@h8bVj?6LDq zTk)A<+seQvhM>3XN|?+Z;)Yp03Fp}JdARa8(di|_b2((vXP8-*;MlV1Q@OM&yfMhG z_w_=i8l<1Q?ml*XMivVUjv5|nhVMN+i&1UeIp-CAU3{_b^^E#6w z@`*Y0Dnm7)gzF5eb7e#{KHUyu%Fw=0!bR#uM~jHYC+;wz3~dZ0oTI3G)FPts8F!dd zhSEX_r>j>SEg~A9*{Fo4wTStszJU5@H(7bKpR|atk@$=|yjO+_LkaI!y9ipuhe&+l z4n4|HZ7AV-Mdh9rF%XGQmwvzug%Te2y5e&=5}yW#QtgP(vv9;8)?$uD;#2I9r4?DN zfrW3Xdl2b{Vs6&D&kPxkptz~IuYXjd(UKRMFJc$MwVOm zDfx5Nd#!!cN2<@OUcWZ?g-h%@!<{M_pQU<>6NW2upLb`TY=bOR1iI9R_gUT-=dmGR zlmd@6IcAtOkg%yZY|W=%-JqrnLG!ekTiWDv)7WsDWQ#{*>zgGX^*%?nYs>E$brg|9 zI_c!FpL&K}TYgoZ%i)|ApHn93M%D_K+cP=R$;V$3*dFnH?FV;MvE)bcN5Tlzo;|cz?x6Lf$#Ob1e tV*mYXK@bE%5ClOG1VIo4K@f!hhu=9=y|&YkHp2h_002ovPDHLkV1mxP*C7A^ literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_down_white_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_down_white_24.png new file mode 100644 index 0000000000000000000000000000000000000000..4ab55abbd148cd347a99dd1231b2a5133be7ceec GIT binary patch literal 356 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z^Lu%;uuoF`1aObUuQ=V)`wTQ z4Gir!x~iX8#OA^saP;lLM(zebgGt5{bju&|akNQId-}Y$Bu)FrrM=57KTQwv(p)+v zXijp9TxS}Xj29f>(J)}f$6UZ|aF#pZ0;k1>S^NtYNHc7BSi{%Ql+ToK{A)ck z7aK#tlUL=8f4?#&96!X{&@0POUUp#ON!|u_>j!7~8ledhL@>OhOmV4W=+D+2PcQx1xjXIQ z-?;n5vzgufd}LeZL>9l0Q%HF;apzeM#mSp{{vG3#-1lqwamo6A;WrIp4h)Pe0x;st bvsy+G&Dw%Qb+K|_=rMS@`njxgN@xNA-1&`c literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_grey600_24.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_grey600_24.png new file mode 100644 index 0000000000000000000000000000000000000000..429dc02df002905271543ae7b7ccdba102fbc4ae GIT binary patch literal 895 zcmV-_1AzRAP)LW}-_Fh3}$AWJPOf+q+nT~wxge_pt~0?gISPD1fE50Xo6}LTMaDo>hPj1QbAO1l!C2i1rBp z)f_Hifdv5BJ_q1>g>nM`qJ0LSYZBYz2hiK+01fEDtcs9DWBdT5eF-462InxLu7-W_ z1L*Ass$T)x@r@$gX5kCNFp92VO!ABDJ z0{QU*@b)=?R4HDQ$SZLIu=Y6sR}tQj#ata10BfHE=qkZzD0UdB7y#7vIe@OMm=)C;e#NLmF5=n=9IS>d(WF2EC7{i*OeWEUWymnm0;&t=O1 zZKV2s;nQOo;5w;ZBYa+324KyV37-#^0VYZH<-+H)Wq>THo-ced9zd7>6B=}V5nm(K zYhC&`+DfV)aOp!3}a*fC(o5<*7bNt z#y%=tdFZadTN2sn%BVpV#!1{Wq}&+xIDrg_N~7F`ahr{JfPiQQ)%FLT3ULwB%FI@s z^^vn;TtHf#nrpH>^tTti$RJQOi(M{{U5=yL<-ynIC~{l0yGEbgF=ZIhL!LD9>4>501w~+Jb(uV7pmJYSR~eKS{(!oQ$RJCI zh#(`Wz*HnCx`?o&;uIG7G1K&P;oX|`PNO+9d&7SA?b>Vk!28a-KbE2F;qiDp9*@W4 zA)nAvju6=%Q{1JEVs{1RN$`-pMBEjaXOz>dwp+j?3kaedBi~j51FC>zg#T<5FrWzN zB)Gydy95jb3#bfIZjXS0bOZ#G?657!U$-Y~lhF=p@*mTLA+? zKpzFP^9_xkH04gfAV?X#jr(ZKQIi`11Crm)X=RpVzEF{U0fRys^Zwxz$-E+xT>*nm zI&({TLo(O0DPTY+&G|*VRbJ-mYzY{GNjFCcqezAcXG6e{iuCjR%M6lJnHMmyAc4FT zxmu7+P>@*x0}B)wW@n0gJxI=GQoz811pvBO9{47F7xTvmXG*}pA_btIje1tjBWcKt zfPp^{fDtyRc~>$iGCWzFz)}&Mw_o3baZY{@*kY#ubm@z2Vj@S2tpc!1t$kZW_1Y^i zqJ9_ZMbuaFY!yJ=LKYGiQGeSj@Jy}#TtpqVR{-@e<+_NuYO_F_QvHC4>9$$mrc%8| z#JsjyK>Op$M9fE<1tyj1Yemdwn+4)Z^@xaxd4XX3BQ)UpOMFAAUhC4&Xsc5Fpi3XJ zQl)yQi0QCb;Hg@@Uqm(AD^Rc0UPD|&{bj4bu)0-g6j4+5ZfNvFt~(;?fvsE0PPOu8 z`2camPJuomYUOr$tU{5E2U|m|Q}eDODl$B_@o2G+^=W6_W8dL!XJB7MDbr&9|Ag&2 zULT@1MZR7nXI#4AIErM974BRyRWXa?ggcjfWsD&iB;S>5)~&oplAzL+i|z{EkxYjx ztp-($lgtakZZvzGBt|k(%3Wx;+0G+0W~jEm;i-_zOrw#Y&i0nGVlELyCr*>yO@I67 zAx02$>~^{Ba-3?H8(&{i;%@8l4=xgRxA}X3N_X4u$7v?d)qjBaz;U_WcSRu1J?i9Q z*$sgxw>Tubgi_@%07*qoM6N<$ Ef==9+1ONa4 literal 0 HcmV?d00001 diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_36.png b/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_36.png new file mode 100644 index 0000000000000000000000000000000000000000..fd633b6cb4437452e127fd47c7f4ce89cd529fe9 GIT binary patch literal 1304 zcmV+z1?T#SP)x-3D6o=oroUt57%_6&6Qjy>6gHY5IP0>Y)P{$YzBCwK%`cO!a3AUANiYSmE8?_0_ zD3F4riOixqeGm-;yE0l*nN2#L8K-Gxob&V#^kZ-0objA@t!I5+yo-l(dG})PwKH=# zj^j9v<2a7vIF92uj^j84+L%H%*^yBz0Wi!C?&C}sqyz!LIK8w}a6w8C0Q|u^X1gFQ z2;d)HWR5LCK?@R$vXQf_2nv7}q$%<+4fz)oATCI^Ar2ug%J2?~%TsGoG;b(-=aC_tj1MsA^pBB|`8xpoC}cpn*XyuN6T7Dj+Ch2_tCWYnp07 zP=E>v%4lT(&^%lHf&x@fP{x%EqM6{T>J}8B!h$lc<8L(kDO9hZ0Fxjn;|?a!JX)=S z0!)&ijK|RoaZWV~3NVR+GTuP5srm#3D2t#1=}VA5 zpkjhxEAy(C z1PyX=r0!<9zW>02Aow_1`4$j+)0!;^g1aJ>UxQ+y4MB$@t<-w@Mds5s1i=H5+FuoU zpIZ_1L*%`>L*$*H-i9E!flLP%qL^nz(3VK`zl*%ZRs{7&zGUx+yvM8vf-A^$ut8*X zn-LUQIII*|y>RvIgu3Dw647rpOwxBWRpV z2L;(Sb3rc1zhX%>^x;3!XyDWM-@N|s^B2XNMb;i)YWPwE0GR*37OO8=5%g!I-Lb=Z zyJK^t`oq>6X4jMHV2<^c>vxgbmx;U~D^2^Ak=nQE7KsHxKU0Vty!%UJcG(cr5#7$I zxYdH7kD`^oEH^Jq&A*^xbaqe+C-`sPC(FB_Qo?)8{U|!~FKAt~>UzGHb7E%aeG_MQ zLKPh-cIAB=aCgE^={okISeEaN;z|543mZ|4a$Y`< zLmf!}<)DocitfA~sB21}#lRsHW6bptGqA7B=^<&}fl+Zk4eXzidjG+03 zM%$w)S{X)jk_EPho3t^A2A;A#9%nhDXka%5y91W$SVIX79OqKIBf4hM8y#J`$nKE0 zHhv+-TB~CM&!C4muh|?l*+?fxi1Qu=d!tGlSjJDJ@Cj3`4ZEGeDh@)To@Ptqk_+6< zHik&$T~4<(aQhhPz$<#)g^z4!wGaK*9Alwh8=?7%xqk78VvIneUtOcv!+iYmBf(KR zsjo;yIk-M+glCvpsd{St0=8kE=UkOxUC^(rW>zG}sGt$v;x=*NnsGrzwsSYr(=x0H zTEo?%x8s6DRGAKKzjY O0000 + + + + + + + + + + + + + + diff --git a/library/dialpad/src/main/res/layout/dialpad.xml b/library/dialpad/src/main/res/layout/dialpad.xml new file mode 100644 index 0000000000..ec8450c7b5 --- /dev/null +++ b/library/dialpad/src/main/res/layout/dialpad.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library/dialpad/src/main/res/layout/dialpad_fragment.xml b/library/dialpad/src/main/res/layout/dialpad_fragment.xml new file mode 100644 index 0000000000..4e9a5f330c --- /dev/null +++ b/library/dialpad/src/main/res/layout/dialpad_fragment.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + diff --git a/library/dialpad/src/main/res/layout/dialpad_key.xml b/library/dialpad/src/main/res/layout/dialpad_key.xml new file mode 100644 index 0000000000..77e4fc53a6 --- /dev/null +++ b/library/dialpad/src/main/res/layout/dialpad_key.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + diff --git a/library/dialpad/src/main/res/layout/dialpad_key_one.xml b/library/dialpad/src/main/res/layout/dialpad_key_one.xml new file mode 100644 index 0000000000..2ef0baa1de --- /dev/null +++ b/library/dialpad/src/main/res/layout/dialpad_key_one.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + diff --git a/library/dialpad/src/main/res/layout/dialpad_key_pound.xml b/library/dialpad/src/main/res/layout/dialpad_key_pound.xml new file mode 100644 index 0000000000..d37a6aa788 --- /dev/null +++ b/library/dialpad/src/main/res/layout/dialpad_key_pound.xml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/library/dialpad/src/main/res/layout/dialpad_key_star.xml b/library/dialpad/src/main/res/layout/dialpad_key_star.xml new file mode 100644 index 0000000000..d288475d01 --- /dev/null +++ b/library/dialpad/src/main/res/layout/dialpad_key_star.xml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/library/dialpad/src/main/res/layout/dialpad_key_zero.xml b/library/dialpad/src/main/res/layout/dialpad_key_zero.xml new file mode 100644 index 0000000000..943ae48dd2 --- /dev/null +++ b/library/dialpad/src/main/res/layout/dialpad_key_zero.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + diff --git a/library/dialpad/src/main/res/layout/dialpad_view.xml b/library/dialpad/src/main/res/layout/dialpad_view.xml new file mode 100644 index 0000000000..fb14ad0989 --- /dev/null +++ b/library/dialpad/src/main/res/layout/dialpad_view.xml @@ -0,0 +1,24 @@ + + + + + + diff --git a/library/dialpad/src/main/res/layout/dialpad_view_unthemed.xml b/library/dialpad/src/main/res/layout/dialpad_view_unthemed.xml new file mode 100644 index 0000000000..1b7b78f907 --- /dev/null +++ b/library/dialpad/src/main/res/layout/dialpad_view_unthemed.xml @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/library/dialpad/src/main/res/values-af/values-af.xml b/library/dialpad/src/main/res/values-af/values-af.xml new file mode 100644 index 0000000000..6a93515ac0 --- /dev/null +++ b/library/dialpad/src/main/res/values-af/values-af.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Gaan terug" + "Meer opsies" + "plus" + "stemboodskap" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-am/values-am.xml b/library/dialpad/src/main/res/values-am/values-am.xml new file mode 100644 index 0000000000..08955ffeec --- /dev/null +++ b/library/dialpad/src/main/res/values-am/values-am.xml @@ -0,0 +1,8 @@ + + + "የኋሊት ደምሳሽ" + "ወደኋላ ያስሱ" + "ተጨማሪ አማራጮች" + "የመደመር ምልክት" + "የድምፅ መልዕክት" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ar/values-ar.xml b/library/dialpad/src/main/res/values-ar/values-ar.xml new file mode 100644 index 0000000000..e791d1e5f2 --- /dev/null +++ b/library/dialpad/src/main/res/values-ar/values-ar.xml @@ -0,0 +1,8 @@ + + + "مسافة للخلف" + "الرجوع" + "مزيد من الخيارات" + "علامة الجمع" + "بريد صوتي" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-az/values-az.xml b/library/dialpad/src/main/res/values-az/values-az.xml new file mode 100644 index 0000000000..152fdea46e --- /dev/null +++ b/library/dialpad/src/main/res/values-az/values-az.xml @@ -0,0 +1,8 @@ + + + "geri düyməsi" + "Geri naviqasiya edin" + "Daha çox seçim" + "plus" + "səsli məktub" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-b+sr+Latn/values-b+sr+Latn.xml b/library/dialpad/src/main/res/values-b+sr+Latn/values-b+sr+Latn.xml new file mode 100644 index 0000000000..4925383c9c --- /dev/null +++ b/library/dialpad/src/main/res/values-b+sr+Latn/values-b+sr+Latn.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Idite nazad" + "Još opcija" + "plus" + "govorna pošta" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-be/values-be.xml b/library/dialpad/src/main/res/values-be/values-be.xml new file mode 100644 index 0000000000..3b795ba0f6 --- /dev/null +++ b/library/dialpad/src/main/res/values-be/values-be.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Перайсці назад" + "Дадатковыя параметры" + "плюс" + "галасавая пошта" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-bg/values-bg.xml b/library/dialpad/src/main/res/values-bg/values-bg.xml new file mode 100644 index 0000000000..aa464b870b --- /dev/null +++ b/library/dialpad/src/main/res/values-bg/values-bg.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Преминаване назад" + "Още опции" + "плюс" + "гласова поща" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-bn/values-bn.xml b/library/dialpad/src/main/res/values-bn/values-bn.xml new file mode 100644 index 0000000000..78efb7eb12 --- /dev/null +++ b/library/dialpad/src/main/res/values-bn/values-bn.xml @@ -0,0 +1,8 @@ + + + "ব্যাক-স্পেস" + "পিছনে যান" + "আরো বিকল্প" + "যোগ চিহ্ন" + "ভয়েসমেল" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-bs/values-bs.xml b/library/dialpad/src/main/res/values-bs/values-bs.xml new file mode 100644 index 0000000000..6782138188 --- /dev/null +++ b/library/dialpad/src/main/res/values-bs/values-bs.xml @@ -0,0 +1,8 @@ + + + "tipka za brisanje" + "Vrati se nazad" + "Više opcija" + "plus" + "govorna pošta" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ca/values-ca.xml b/library/dialpad/src/main/res/values-ca/values-ca.xml new file mode 100644 index 0000000000..b4c70bdc49 --- /dev/null +++ b/library/dialpad/src/main/res/values-ca/values-ca.xml @@ -0,0 +1,8 @@ + + + "retrocés" + "Torna enrere" + "Més opcions" + "més" + "missatge de veu" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-cs/values-cs.xml b/library/dialpad/src/main/res/values-cs/values-cs.xml new file mode 100644 index 0000000000..b9f770215c --- /dev/null +++ b/library/dialpad/src/main/res/values-cs/values-cs.xml @@ -0,0 +1,8 @@ + + + "Backspace" + "Přejít zpět" + "Více možností" + "plus" + "hlasová zpráva" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-da/values-da.xml b/library/dialpad/src/main/res/values-da/values-da.xml new file mode 100644 index 0000000000..b842e27303 --- /dev/null +++ b/library/dialpad/src/main/res/values-da/values-da.xml @@ -0,0 +1,8 @@ + + + "tilbagetast" + "Naviger tilbage" + "Flere valgmuligheder" + "plus" + "telefonsvarer" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-de/values-de.xml b/library/dialpad/src/main/res/values-de/values-de.xml new file mode 100644 index 0000000000..7d3f7b9a77 --- /dev/null +++ b/library/dialpad/src/main/res/values-de/values-de.xml @@ -0,0 +1,8 @@ + + + "Rücktaste" + "Zurück" + "Mehr Optionen" + "Plus" + "Mailboxnachricht" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-el/values-el.xml b/library/dialpad/src/main/res/values-el/values-el.xml new file mode 100644 index 0000000000..1998e9e464 --- /dev/null +++ b/library/dialpad/src/main/res/values-el/values-el.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Μετάβαση πίσω" + "Περισσότερες επιλογές" + "συν" + "αυτόματος τηλεφωνητής" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-en-rAU/values-en-rAU.xml b/library/dialpad/src/main/res/values-en-rAU/values-en-rAU.xml new file mode 100644 index 0000000000..5281387a9d --- /dev/null +++ b/library/dialpad/src/main/res/values-en-rAU/values-en-rAU.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Navigate back" + "More options" + "plus" + "voicemail" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-en-rGB/values-en-rGB.xml b/library/dialpad/src/main/res/values-en-rGB/values-en-rGB.xml new file mode 100644 index 0000000000..5281387a9d --- /dev/null +++ b/library/dialpad/src/main/res/values-en-rGB/values-en-rGB.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Navigate back" + "More options" + "plus" + "voicemail" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-en-rIN/values-en-rIN.xml b/library/dialpad/src/main/res/values-en-rIN/values-en-rIN.xml new file mode 100644 index 0000000000..5281387a9d --- /dev/null +++ b/library/dialpad/src/main/res/values-en-rIN/values-en-rIN.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Navigate back" + "More options" + "plus" + "voicemail" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-es-rUS/values-es-rUS.xml b/library/dialpad/src/main/res/values-es-rUS/values-es-rUS.xml new file mode 100644 index 0000000000..0eda697d16 --- /dev/null +++ b/library/dialpad/src/main/res/values-es-rUS/values-es-rUS.xml @@ -0,0 +1,8 @@ + + + "retroceso" + "Volver" + "Más opciones" + "más" + "buzón de voz" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-es/values-es.xml b/library/dialpad/src/main/res/values-es/values-es.xml new file mode 100644 index 0000000000..3386a4e7e9 --- /dev/null +++ b/library/dialpad/src/main/res/values-es/values-es.xml @@ -0,0 +1,8 @@ + + + "retroceso" + "Volver" + "Más opciones" + "más" + "mensaje de voz" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-et/values-et.xml b/library/dialpad/src/main/res/values-et/values-et.xml new file mode 100644 index 0000000000..05499ef49f --- /dev/null +++ b/library/dialpad/src/main/res/values-et/values-et.xml @@ -0,0 +1,8 @@ + + + "tagasilüke" + "Tagasi navigeerimine" + "Rohkem valikuid" + "pluss" + "kõnepostisõnum" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-eu/values-eu.xml b/library/dialpad/src/main/res/values-eu/values-eu.xml new file mode 100644 index 0000000000..788a168eb6 --- /dev/null +++ b/library/dialpad/src/main/res/values-eu/values-eu.xml @@ -0,0 +1,8 @@ + + + "atzera tekla" + "Egin atzera" + "Aukera gehiago" + "gehi" + "erantzungailua" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-fa/values-fa.xml b/library/dialpad/src/main/res/values-fa/values-fa.xml new file mode 100644 index 0000000000..e28807f063 --- /dev/null +++ b/library/dialpad/src/main/res/values-fa/values-fa.xml @@ -0,0 +1,8 @@ + + + "برگشت به عقب" + "پیمایش به عقب" + "گزینه‌های بیشتر" + "به‌علاوه" + "پست صوتی" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-fi/values-fi.xml b/library/dialpad/src/main/res/values-fi/values-fi.xml new file mode 100644 index 0000000000..30ec4d5c8c --- /dev/null +++ b/library/dialpad/src/main/res/values-fi/values-fi.xml @@ -0,0 +1,8 @@ + + + "askelpalautin" + "Siirry takaisin" + "Lisää vaihtoehtoja" + "plus" + "ääniviesti" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-fr-rCA/values-fr-rCA.xml b/library/dialpad/src/main/res/values-fr-rCA/values-fr-rCA.xml new file mode 100644 index 0000000000..e2dc9e4527 --- /dev/null +++ b/library/dialpad/src/main/res/values-fr-rCA/values-fr-rCA.xml @@ -0,0 +1,8 @@ + + + "retour arrière" + "Naviguer vers l\'arrière" + "Plus d\'options" + "plus" + "messagerie vocale" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-fr/values-fr.xml b/library/dialpad/src/main/res/values-fr/values-fr.xml new file mode 100644 index 0000000000..265b089baf --- /dev/null +++ b/library/dialpad/src/main/res/values-fr/values-fr.xml @@ -0,0 +1,8 @@ + + + "retour arrière" + "Revenir en arrière" + "Plus d\'options" + "plus" + "message vocal" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-gl/values-gl.xml b/library/dialpad/src/main/res/values-gl/values-gl.xml new file mode 100644 index 0000000000..932feba9df --- /dev/null +++ b/library/dialpad/src/main/res/values-gl/values-gl.xml @@ -0,0 +1,8 @@ + + + "retroceso" + "Volver á vista anterior" + "Máis opcións" + "máis" + "correo de voz" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-gu/values-gu.xml b/library/dialpad/src/main/res/values-gu/values-gu.xml new file mode 100644 index 0000000000..78997a8be6 --- /dev/null +++ b/library/dialpad/src/main/res/values-gu/values-gu.xml @@ -0,0 +1,8 @@ + + + "backspace" + "પાછળ નૅવિગેટ કરો" + "વધુ વિકલ્પો" + "પ્લસ" + "વૉઇસમેઇલ" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-hi/values-hi.xml b/library/dialpad/src/main/res/values-hi/values-hi.xml new file mode 100644 index 0000000000..cc10b134ee --- /dev/null +++ b/library/dialpad/src/main/res/values-hi/values-hi.xml @@ -0,0 +1,8 @@ + + + "backspace" + "वापस नेविगेट करें" + "अधिक विकल्प" + "धन का चिह्न" + "वॉइसमेल" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-hr/values-hr.xml b/library/dialpad/src/main/res/values-hr/values-hr.xml new file mode 100644 index 0000000000..19f1922c5f --- /dev/null +++ b/library/dialpad/src/main/res/values-hr/values-hr.xml @@ -0,0 +1,8 @@ + + + "povratna tipka" + "Kretanje natrag" + "Više opcija" + "plus" + "govorna pošta" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-hu/values-hu.xml b/library/dialpad/src/main/res/values-hu/values-hu.xml new file mode 100644 index 0000000000..4aa7a3943d --- /dev/null +++ b/library/dialpad/src/main/res/values-hu/values-hu.xml @@ -0,0 +1,8 @@ + + + "Backspace" + "Vissza" + "További beállítások" + "plusz" + "hangposta" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-hy/values-hy.xml b/library/dialpad/src/main/res/values-hy/values-hy.xml new file mode 100644 index 0000000000..0c13c0e156 --- /dev/null +++ b/library/dialpad/src/main/res/values-hy/values-hy.xml @@ -0,0 +1,8 @@ + + + "հետշարժ" + "Հետ գնալ" + "Այլ ընտրանքներ" + "գումարում" + "ձայնային փոստ" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-in/values-in.xml b/library/dialpad/src/main/res/values-in/values-in.xml new file mode 100644 index 0000000000..9384f9c220 --- /dev/null +++ b/library/dialpad/src/main/res/values-in/values-in.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Tombol kembali" + "Opsi lainnya" + "tambah" + "pesan suara" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-is/values-is.xml b/library/dialpad/src/main/res/values-is/values-is.xml new file mode 100644 index 0000000000..bbf02c8e91 --- /dev/null +++ b/library/dialpad/src/main/res/values-is/values-is.xml @@ -0,0 +1,8 @@ + + + "bakklykill" + "Fara til baka" + "Fleiri valkostir" + "plús" + "talhólfsskilaboð" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-it/values-it.xml b/library/dialpad/src/main/res/values-it/values-it.xml new file mode 100644 index 0000000000..563975ce15 --- /dev/null +++ b/library/dialpad/src/main/res/values-it/values-it.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Torna indietro" + "Altre opzioni" + "più" + "messaggio vocale" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-iw/values-iw.xml b/library/dialpad/src/main/res/values-iw/values-iw.xml new file mode 100644 index 0000000000..34493a8ac6 --- /dev/null +++ b/library/dialpad/src/main/res/values-iw/values-iw.xml @@ -0,0 +1,8 @@ + + + "Backspace" + "ניווט חזרה" + "אפשרויות נוספות" + "פלוס" + "דואר קולי" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ja/values-ja.xml b/library/dialpad/src/main/res/values-ja/values-ja.xml new file mode 100644 index 0000000000..b8c17100c2 --- /dev/null +++ b/library/dialpad/src/main/res/values-ja/values-ja.xml @@ -0,0 +1,8 @@ + + + "Backspace" + "戻る" + "その他のオプション" + "足す" + "ボイスメール" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ka/values-ka.xml b/library/dialpad/src/main/res/values-ka/values-ka.xml new file mode 100644 index 0000000000..2613d048a4 --- /dev/null +++ b/library/dialpad/src/main/res/values-ka/values-ka.xml @@ -0,0 +1,8 @@ + + + "უკუშლა" + "უკან დაბრუნება" + "სხვა პარამეტრები" + "პლუსი" + "ხმოვანი ფოსტა" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-kk/values-kk.xml b/library/dialpad/src/main/res/values-kk/values-kk.xml new file mode 100644 index 0000000000..65015a6e66 --- /dev/null +++ b/library/dialpad/src/main/res/values-kk/values-kk.xml @@ -0,0 +1,8 @@ + + + "Backspace пернесі" + "Артқа қайту" + "Басқа опциялар" + "қосу" + "дауыстық пошта" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-km/values-km.xml b/library/dialpad/src/main/res/values-km/values-km.xml new file mode 100644 index 0000000000..bb4754c842 --- /dev/null +++ b/library/dialpad/src/main/res/values-km/values-km.xml @@ -0,0 +1,8 @@ + + + "លុប​ថយក្រោយ" + "រក​មើលថយ​ក្រោយ​វិញ" + "ជម្រើស​បន្ថែម" + "plus" + "សារ​ជា​សំឡេង" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-kn/values-kn.xml b/library/dialpad/src/main/res/values-kn/values-kn.xml new file mode 100644 index 0000000000..e49a0633bc --- /dev/null +++ b/library/dialpad/src/main/res/values-kn/values-kn.xml @@ -0,0 +1,8 @@ + + + "backspace" + "ಹಿಂದಕ್ಕೆ ನ್ಯಾವಿಗೇಟ್ ಮಾಡು" + "ಇನ್ನಷ್ಟು ಆಯ್ಕೆಗಳು" + "ಸಂಕಲನ" + "ಧ್ವನಿಮೇಲ್" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ko/values-ko.xml b/library/dialpad/src/main/res/values-ko/values-ko.xml new file mode 100644 index 0000000000..f9ebed349a --- /dev/null +++ b/library/dialpad/src/main/res/values-ko/values-ko.xml @@ -0,0 +1,8 @@ + + + "백스페이스" + "뒤로 이동" + "옵션 더보기" + "더하기" + "음성사서함" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ky/values-ky.xml b/library/dialpad/src/main/res/values-ky/values-ky.xml new file mode 100644 index 0000000000..a894cd7cf2 --- /dev/null +++ b/library/dialpad/src/main/res/values-ky/values-ky.xml @@ -0,0 +1,8 @@ + + + "артка карай өчүрүү" + "Артка кайтуу" + "Көбүрөөк мүмкүнчүлүктөр" + "кошуу" + "үн почтасы" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-land/values-land.xml b/library/dialpad/src/main/res/values-land/values-land.xml new file mode 100644 index 0000000000..364bf95f05 --- /dev/null +++ b/library/dialpad/src/main/res/values-land/values-land.xml @@ -0,0 +1,25 @@ + + + 65dp + 5dp + 20sp + 3dp + 35dp + 0dp + + + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-lo/values-lo.xml b/library/dialpad/src/main/res/values-lo/values-lo.xml new file mode 100644 index 0000000000..e73d68cc95 --- /dev/null +++ b/library/dialpad/src/main/res/values-lo/values-lo.xml @@ -0,0 +1,8 @@ + + + "ປຸ່ມ backspace" + "ນຳທາງກັບຄືນ" + "ໂຕເລືອກເພີ່ມເຕີມ" + "ບວກ" + "ຂໍ້ຄວາມສຽງ" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-lt/values-lt.xml b/library/dialpad/src/main/res/values-lt/values-lt.xml new file mode 100644 index 0000000000..858ca29dc9 --- /dev/null +++ b/library/dialpad/src/main/res/values-lt/values-lt.xml @@ -0,0 +1,8 @@ + + + "naikinimo klavišas" + "Eiti atgal" + "Daugiau parinkčių" + "sudėties ženklas" + "balso pašto pranešimas" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-lv/values-lv.xml b/library/dialpad/src/main/res/values-lv/values-lv.xml new file mode 100644 index 0000000000..70a59dc3b5 --- /dev/null +++ b/library/dialpad/src/main/res/values-lv/values-lv.xml @@ -0,0 +1,8 @@ + + + "atpakaļatkāpe" + "Pāriet atpakaļ" + "Vairāk opciju" + "pluszīme" + "balss pasts" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-mk/values-mk.xml b/library/dialpad/src/main/res/values-mk/values-mk.xml new file mode 100644 index 0000000000..0f958f19a0 --- /dev/null +++ b/library/dialpad/src/main/res/values-mk/values-mk.xml @@ -0,0 +1,8 @@ + + + "избриши" + "Оди назад" + "Повеќе опции" + "плус" + "говорна пошта" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ml/values-ml.xml b/library/dialpad/src/main/res/values-ml/values-ml.xml new file mode 100644 index 0000000000..43dbec3911 --- /dev/null +++ b/library/dialpad/src/main/res/values-ml/values-ml.xml @@ -0,0 +1,8 @@ + + + "ബാക്ക്‌സ്‌പെയ്‌സ്" + "തിരികെ പോകുക" + "കൂടുതൽ‍ ഓപ്‌ഷനുകള്‍" + "പ്ലസ്" + "വോയ്‌സ്‌മെയിൽ" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-mn/values-mn.xml b/library/dialpad/src/main/res/values-mn/values-mn.xml new file mode 100644 index 0000000000..86e965baf5 --- /dev/null +++ b/library/dialpad/src/main/res/values-mn/values-mn.xml @@ -0,0 +1,8 @@ + + + "ухраах" + "Буцах" + "Нэмэлт сонголтууд" + "нэмэх" + "дуут шуудан" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-mr/values-mr.xml b/library/dialpad/src/main/res/values-mr/values-mr.xml new file mode 100644 index 0000000000..385a98df01 --- /dev/null +++ b/library/dialpad/src/main/res/values-mr/values-mr.xml @@ -0,0 +1,8 @@ + + + "backspace" + "मागे नेव्हिगेट करा" + "अधिक पर्याय" + "अधिक" + "व्हॉइसमेल" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ms/values-ms.xml b/library/dialpad/src/main/res/values-ms/values-ms.xml new file mode 100644 index 0000000000..a41274606d --- /dev/null +++ b/library/dialpad/src/main/res/values-ms/values-ms.xml @@ -0,0 +1,8 @@ + + + "undur ruang" + "Navigasi kembali" + "Lagi pilihan" + "tambah" + "mel suara" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-my/values-my.xml b/library/dialpad/src/main/res/values-my/values-my.xml new file mode 100644 index 0000000000..7e1ff4231c --- /dev/null +++ b/library/dialpad/src/main/res/values-my/values-my.xml @@ -0,0 +1,8 @@ + + + "နောက်ပြန်ဖျက်ခလုတ်" + "အနောက်သို့ ပြန်သွားပါ" + "ပိုမိုရွေးချယ်စရာများ" + "အပေါင်း လက္ခဏာ" + "အသံမေးလ်" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-nb/values-nb.xml b/library/dialpad/src/main/res/values-nb/values-nb.xml new file mode 100644 index 0000000000..cd08c3b339 --- /dev/null +++ b/library/dialpad/src/main/res/values-nb/values-nb.xml @@ -0,0 +1,8 @@ + + + "tilbaketast" + "Gå tilbake" + "Flere alternativer" + "pluss" + "talepost" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ne/values-ne.xml b/library/dialpad/src/main/res/values-ne/values-ne.xml new file mode 100644 index 0000000000..28ec947b80 --- /dev/null +++ b/library/dialpad/src/main/res/values-ne/values-ne.xml @@ -0,0 +1,8 @@ + + + "ब्याकस्पेस" + "पछाडि नेभिगेट गर्नुहोस्" + "थप विकल्पहरू" + "जोड" + "भ्वाइसमेल" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-nl/values-nl.xml b/library/dialpad/src/main/res/values-nl/values-nl.xml new file mode 100644 index 0000000000..6e3badad9d --- /dev/null +++ b/library/dialpad/src/main/res/values-nl/values-nl.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Terug navigeren" + "Meer opties" + "plus" + "voicemail" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-no/values-no.xml b/library/dialpad/src/main/res/values-no/values-no.xml new file mode 100644 index 0000000000..cd08c3b339 --- /dev/null +++ b/library/dialpad/src/main/res/values-no/values-no.xml @@ -0,0 +1,8 @@ + + + "tilbaketast" + "Gå tilbake" + "Flere alternativer" + "pluss" + "talepost" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-pa/values-pa.xml b/library/dialpad/src/main/res/values-pa/values-pa.xml new file mode 100644 index 0000000000..add9e7a3bd --- /dev/null +++ b/library/dialpad/src/main/res/values-pa/values-pa.xml @@ -0,0 +1,8 @@ + + + "ਬੈਕਸਪੇਸ" + "ਪਿੱਛੇ ਆਵਾਗੌਣ ਕਰੋ" + "ਹੋਰ ਚੋਣਾਂ" + "ਪਲਸ" + "ਵੌਇਸਮੇਲ" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-pl/values-pl.xml b/library/dialpad/src/main/res/values-pl/values-pl.xml new file mode 100644 index 0000000000..94c00bb06a --- /dev/null +++ b/library/dialpad/src/main/res/values-pl/values-pl.xml @@ -0,0 +1,8 @@ + + + "usuń" + "Wstecz" + "Więcej opcji" + "plus" + "poczta głosowa" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-pt-rBR/values-pt-rBR.xml b/library/dialpad/src/main/res/values-pt-rBR/values-pt-rBR.xml new file mode 100644 index 0000000000..49ae0d6428 --- /dev/null +++ b/library/dialpad/src/main/res/values-pt-rBR/values-pt-rBR.xml @@ -0,0 +1,8 @@ + + + "voltar" + "Voltar" + "Mais opções" + "mais" + "correio de voz" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-pt-rPT/values-pt-rPT.xml b/library/dialpad/src/main/res/values-pt-rPT/values-pt-rPT.xml new file mode 100644 index 0000000000..5d42ca8b61 --- /dev/null +++ b/library/dialpad/src/main/res/values-pt-rPT/values-pt-rPT.xml @@ -0,0 +1,8 @@ + + + "retrocesso" + "Navegar para trás" + "Mais opções" + "mais" + "mensagem de correio de voz" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-pt/values-pt.xml b/library/dialpad/src/main/res/values-pt/values-pt.xml new file mode 100644 index 0000000000..49ae0d6428 --- /dev/null +++ b/library/dialpad/src/main/res/values-pt/values-pt.xml @@ -0,0 +1,8 @@ + + + "voltar" + "Voltar" + "Mais opções" + "mais" + "correio de voz" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ro/values-ro.xml b/library/dialpad/src/main/res/values-ro/values-ro.xml new file mode 100644 index 0000000000..34f7e9fe03 --- /dev/null +++ b/library/dialpad/src/main/res/values-ro/values-ro.xml @@ -0,0 +1,8 @@ + + + "tasta backspace" + "Navigați înapoi" + "Mai multe opțiuni" + "plus" + "mesaj vocal" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ru/values-ru.xml b/library/dialpad/src/main/res/values-ru/values-ru.xml new file mode 100644 index 0000000000..261fdf0ee6 --- /dev/null +++ b/library/dialpad/src/main/res/values-ru/values-ru.xml @@ -0,0 +1,8 @@ + + + "клавиша Backspace" + "Вернуться" + "Ещё" + "плюс" + "голосовая почта" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-si/values-si.xml b/library/dialpad/src/main/res/values-si/values-si.xml new file mode 100644 index 0000000000..09a999100f --- /dev/null +++ b/library/dialpad/src/main/res/values-si/values-si.xml @@ -0,0 +1,8 @@ + + + "backspace බොත්තම" + "ආපසු සංචාලනය කරන්න" + "තවත් විකල්ප" + "ධන" + "හඬ තැපෑල" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-sk/values-sk.xml b/library/dialpad/src/main/res/values-sk/values-sk.xml new file mode 100644 index 0000000000..6b8990a941 --- /dev/null +++ b/library/dialpad/src/main/res/values-sk/values-sk.xml @@ -0,0 +1,8 @@ + + + "spätné mazanie" + "Prejsť späť" + "Ďalšie možnosti" + "plus" + "hlasová správa" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-sl/values-sl.xml b/library/dialpad/src/main/res/values-sl/values-sl.xml new file mode 100644 index 0000000000..2abde10f12 --- /dev/null +++ b/library/dialpad/src/main/res/values-sl/values-sl.xml @@ -0,0 +1,8 @@ + + + "vračalka" + "Pomik nazaj" + "Več možnosti" + "plus" + "sporočilo v odzivniku" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-sq/values-sq.xml b/library/dialpad/src/main/res/values-sq/values-sq.xml new file mode 100644 index 0000000000..22400298fb --- /dev/null +++ b/library/dialpad/src/main/res/values-sq/values-sq.xml @@ -0,0 +1,8 @@ + + + "kthim prapa" + "Kthehu prapa" + "Opsione të tjera" + "plus" + "postë zanore" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-sr/values-sr.xml b/library/dialpad/src/main/res/values-sr/values-sr.xml new file mode 100644 index 0000000000..6f1beb2900 --- /dev/null +++ b/library/dialpad/src/main/res/values-sr/values-sr.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Идите назад" + "Још опција" + "плус" + "говорна пошта" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-sv/values-sv.xml b/library/dialpad/src/main/res/values-sv/values-sv.xml new file mode 100644 index 0000000000..25de9491a7 --- /dev/null +++ b/library/dialpad/src/main/res/values-sv/values-sv.xml @@ -0,0 +1,8 @@ + + + "backsteg" + "Tillbaka" + "Fler alternativ" + "plus" + "röstbrevlåda" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-sw/values-sw.xml b/library/dialpad/src/main/res/values-sw/values-sw.xml new file mode 100644 index 0000000000..e4273eca9a --- /dev/null +++ b/library/dialpad/src/main/res/values-sw/values-sw.xml @@ -0,0 +1,8 @@ + + + "nafasi ya nyuma" + "Rudi nyuma" + "Chaguo zaidi" + "jumlisha" + "ujumbe wa sauti" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ta/values-ta.xml b/library/dialpad/src/main/res/values-ta/values-ta.xml new file mode 100644 index 0000000000..1412f6ae92 --- /dev/null +++ b/library/dialpad/src/main/res/values-ta/values-ta.xml @@ -0,0 +1,8 @@ + + + "பேக்ஸ்பேஸ்" + "பின் செல்லும்" + "மேலும் விருப்பங்கள்" + "பிளஸ்" + "குரலஞ்சல்" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-te/values-te.xml b/library/dialpad/src/main/res/values-te/values-te.xml new file mode 100644 index 0000000000..ad60e2fd31 --- /dev/null +++ b/library/dialpad/src/main/res/values-te/values-te.xml @@ -0,0 +1,8 @@ + + + "బ్యాక్‌స్పేస్" + "వెనుకకు నావిగేట్ చేస్తుంది" + "మరిన్ని ఎంపికలు" + "కూడిక" + "వాయిస్ మెయిల్" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-th/values-th.xml b/library/dialpad/src/main/res/values-th/values-th.xml new file mode 100644 index 0000000000..a9240af28a --- /dev/null +++ b/library/dialpad/src/main/res/values-th/values-th.xml @@ -0,0 +1,8 @@ + + + "ลบถอยหลัง" + "ย้อนกลับ" + "ตัวเลือกเพิ่มเติม" + "บวก" + "ข้อความเสียง" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-tl/values-tl.xml b/library/dialpad/src/main/res/values-tl/values-tl.xml new file mode 100644 index 0000000000..f5ec293cc3 --- /dev/null +++ b/library/dialpad/src/main/res/values-tl/values-tl.xml @@ -0,0 +1,8 @@ + + + "backspace" + "Nagna-navigate pabalik" + "Higit pang mga pagpipilian" + "plus" + "voicemail" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-tr/values-tr.xml b/library/dialpad/src/main/res/values-tr/values-tr.xml new file mode 100644 index 0000000000..6006ed5857 --- /dev/null +++ b/library/dialpad/src/main/res/values-tr/values-tr.xml @@ -0,0 +1,8 @@ + + + "geri tuşu" + "Geri dön" + "Diğer seçenekler" + "artı" + "sesli mesaj" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-uk/values-uk.xml b/library/dialpad/src/main/res/values-uk/values-uk.xml new file mode 100644 index 0000000000..0d235facdf --- /dev/null +++ b/library/dialpad/src/main/res/values-uk/values-uk.xml @@ -0,0 +1,8 @@ + + + "видалення символів перед курсором" + "Назад" + "Інші варіанти" + "плюс" + "голосова пошта" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-ur/values-ur.xml b/library/dialpad/src/main/res/values-ur/values-ur.xml new file mode 100644 index 0000000000..721322d66d --- /dev/null +++ b/library/dialpad/src/main/res/values-ur/values-ur.xml @@ -0,0 +1,8 @@ + + + "بیک اسپیس" + "پیچھے کو نیویگیٹ کریں" + "مزید اختیارات" + "جمع" + "صوتی میل" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-uz/values-uz.xml b/library/dialpad/src/main/res/values-uz/values-uz.xml new file mode 100644 index 0000000000..74e39230ef --- /dev/null +++ b/library/dialpad/src/main/res/values-uz/values-uz.xml @@ -0,0 +1,8 @@ + + + "orqaga" + "Orqaga qaytish" + "Boshqa parametrlar" + "qo‘shuv belgisi" + "ovozli pochta" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-vi/values-vi.xml b/library/dialpad/src/main/res/values-vi/values-vi.xml new file mode 100644 index 0000000000..cc83289497 --- /dev/null +++ b/library/dialpad/src/main/res/values-vi/values-vi.xml @@ -0,0 +1,8 @@ + + + "phím lùi" + "Điều hướng trở lại" + "Tùy chọn khác" + "cộng" + "thư thoại" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-zh-rCN/values-zh-rCN.xml b/library/dialpad/src/main/res/values-zh-rCN/values-zh-rCN.xml new file mode 100644 index 0000000000..95bc2d1160 --- /dev/null +++ b/library/dialpad/src/main/res/values-zh-rCN/values-zh-rCN.xml @@ -0,0 +1,8 @@ + + + "删除" + "返回" + "更多选项" + "加号" + "语音邮件" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-zh-rHK/values-zh-rHK.xml b/library/dialpad/src/main/res/values-zh-rHK/values-zh-rHK.xml new file mode 100644 index 0000000000..6631ffe940 --- /dev/null +++ b/library/dialpad/src/main/res/values-zh-rHK/values-zh-rHK.xml @@ -0,0 +1,8 @@ + + + "退格鍵" + "返回" + "更多選項" + "加號" + "留言" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-zh-rTW/values-zh-rTW.xml b/library/dialpad/src/main/res/values-zh-rTW/values-zh-rTW.xml new file mode 100644 index 0000000000..bb486569a0 --- /dev/null +++ b/library/dialpad/src/main/res/values-zh-rTW/values-zh-rTW.xml @@ -0,0 +1,8 @@ + + + "Backspace 鍵" + "返回" + "更多選項" + "加號" + "語音留言" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values-zu/values-zu.xml b/library/dialpad/src/main/res/values-zu/values-zu.xml new file mode 100644 index 0000000000..023f3aec62 --- /dev/null +++ b/library/dialpad/src/main/res/values-zu/values-zu.xml @@ -0,0 +1,8 @@ + + + "i-backspace" + "Zulazula uye emuva" + "Izinketho eziningi" + "hlanganisa" + "ivoyisimeyili" + \ No newline at end of file diff --git a/library/dialpad/src/main/res/values/values.xml b/library/dialpad/src/main/res/values/values.xml new file mode 100644 index 0000000000..71d9b27cef --- /dev/null +++ b/library/dialpad/src/main/res/values/values.xml @@ -0,0 +1,121 @@ + + + + #fcfcfc + #ececec + #333 + #89000000 + #10000000 + #737373 + #dadada + #919191 + + 80dp + 2dp + 3dp + 60dp + 8dp + 10dp + 16dp + 24sp + 34sp + 5dp + 100dp + 64dp + 12sp + 3dp + 36sp + 18sp + 23sp + 36sp + 8dp + 14dp + 8dp + 13dp + 2dp + 1dp + 10dp + 400 + 400 + backspace + Navigate back + More options + plus + voicemail + + + + ABC + DEF + GHI + JKL + MNO + PQRS + TUV + WXYZ + + # + + * + + + + + + + + + \ No newline at end of file diff --git a/library/ui-styles/build.gradle b/library/ui-styles/build.gradle index c85f26dbc4..804eb3aae9 100644 --- a/library/ui-styles/build.gradle +++ b/library/ui-styles/build.gradle @@ -58,5 +58,5 @@ dependencies { // Pref theme implementation libs.androidx.preferenceKtx // dialpad dimen - implementation 'im.dlg:android-dialer:1.2.5' + implementation project(":library:dialpad") } diff --git a/settings.gradle b/settings.gradle index e5b5511b94..e43d1f6d75 100644 --- a/settings.gradle +++ b/settings.gradle @@ -9,4 +9,5 @@ include ':library:jsonviewer' include ':library:attachment-viewer' include ':library:diff-match-patch' include ':library:multipicker' +include ':library:dialpad' include ':matrix-sdk-android-flow' diff --git a/vector/build.gradle b/vector/build.gradle index ac3699454c..67e3f92ee5 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -265,7 +265,7 @@ dependencies { api libs.vanniktech.emojiMaterial api libs.vanniktech.emojiGoogle - implementation 'im.dlg:android-dialer:1.2.5' + implementation project(":library:dialpad") // JWT api libs.jsonwebtoken.jjwtApi From abd70d953b503e6b8115416cfb3f652331605875 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Thu, 15 Sep 2022 16:08:46 +0100 Subject: [PATCH 014/187] disabling lint for the pulled in module --- library/dialpad/build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/dialpad/build.gradle b/library/dialpad/build.gradle index 6546b59f4a..4f4c3393e4 100644 --- a/library/dialpad/build.gradle +++ b/library/dialpad/build.gradle @@ -22,3 +22,9 @@ android { dependencies { implementation "com.android.support:appcompat-v7:28.0.0" } + +afterEvaluate { + tasks.findAll { it.name.startsWith("lint") }.each { + it.enabled = false + } +} From e83fa9c81f97371f5434524bf893d78bc8a1cbce Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Fri, 16 Sep 2022 11:41:34 +0100 Subject: [PATCH 015/187] removing dialpad reliance on the legacy support library --- library/dialpad/build.gradle | 4 ---- .../java/com/android/dialer/dialpadview/DialpadTextView.java | 4 +--- .../java/com/android/dialer/widget/ResizingTextEditText.java | 5 +---- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/library/dialpad/build.gradle b/library/dialpad/build.gradle index 4f4c3393e4..1f91deeeb5 100644 --- a/library/dialpad/build.gradle +++ b/library/dialpad/build.gradle @@ -19,10 +19,6 @@ android { } } -dependencies { - implementation "com.android.support:appcompat-v7:28.0.0" -} - afterEvaluate { tasks.findAll { it.name.startsWith("lint") }.each { it.enabled = false diff --git a/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java b/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java index 992d6cbed2..5b1b7bb5dc 100644 --- a/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java +++ b/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java @@ -23,8 +23,6 @@ import android.graphics.Rect; import android.util.AttributeSet; import android.widget.TextView; -import androidx.appcompat.widget.AppCompatTextView; - /** * This is a custom text view intended only for rendering the numerals (and star and pound) on the * dialpad. TextView has built in top/bottom padding to help account for ascenders/descenders. @@ -33,7 +31,7 @@ import androidx.appcompat.widget.AppCompatTextView; * to a larger default, for the dialpad we use this class to more precisely render characters * according to the precise amount of space they need. */ -public class DialpadTextView extends AppCompatTextView { +public class DialpadTextView extends TextView { private Rect mTextBounds = new Rect(); private String mTextStr; diff --git a/library/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java b/library/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java index 6ec1261f15..216175981b 100644 --- a/library/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java +++ b/library/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java @@ -20,14 +20,11 @@ import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import android.widget.EditText; - -import androidx.appcompat.widget.AppCompatEditText; - import com.android.dialer.dialpadview.R; import com.android.dialer.util.ViewUtil; /** EditText which resizes dynamically with respect to text length. */ -public class ResizingTextEditText extends AppCompatEditText { +public class ResizingTextEditText extends EditText { private final int mOriginalTextSize; private final int mMinTextSize; From 739a513f8946ede86a36ce5e40ef8d698202f31e Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Fri, 16 Sep 2022 11:45:20 +0100 Subject: [PATCH 016/187] moving external library modules to an external directory --- build.gradle | 2 +- library/{ => external}/dialpad/build.gradle | 0 .../dialpad/src/main/AndroidManifest.xml | 0 .../com/android/dialer/animation/AnimUtils.java | 0 .../dialer/compat/PathInterpolatorCompat.java | 0 .../dialer/dialpadview/DialpadKeyButton.java | 0 .../android/dialer/dialpadview/DialpadTextView.java | 0 .../com/android/dialer/dialpadview/DialpadView.java | 0 .../android/dialer/dialpadview/DigitsEditText.java | 0 .../main/java/com/android/dialer/util/ViewUtil.java | 0 .../android/dialer/widget/ResizingTextEditText.java | 0 .../quantum_ic_arrow_back_white_24.png | Bin .../quantum_ic_arrow_drop_down_white_18.png | Bin .../quantum_ic_backspace_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_block_white_24.png | Bin .../quantum_ic_bluetooth_audio_grey600_24.png | Bin .../quantum_ic_bluetooth_audio_white_36.png | Bin .../quantum_ic_call_end_white_24.png | Bin .../quantum_ic_call_end_white_36.png | Bin .../quantum_ic_call_made_white_24.png | Bin .../quantum_ic_call_merge_white_36.png | Bin .../quantum_ic_call_missed_white_24.png | Bin .../quantum_ic_call_received_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_call_white_18.png | Bin .../drawable-hdpi-v4/quantum_ic_call_white_24.png | Bin .../quantum_ic_camera_alt_white_24.png | Bin .../quantum_ic_camera_alt_white_48.png | Bin .../drawable-hdpi-v4/quantum_ic_check_black_24.png | Bin .../quantum_ic_check_circle_googblue_24.png | Bin .../drawable-hdpi-v4/quantum_ic_close_white_24.png | Bin .../quantum_ic_content_copy_grey600_24.png | Bin .../drawable-hdpi-v4/quantum_ic_delete_white_24.png | Bin .../quantum_ic_dialpad_white_24.png | Bin .../quantum_ic_dialpad_white_36.png | Bin .../drawable-hdpi-v4/quantum_ic_edit_grey600_24.png | Bin .../quantum_ic_forward_white_24.png | Bin .../quantum_ic_fullscreen_exit_white_48.png | Bin .../quantum_ic_fullscreen_white_48.png | Bin .../drawable-hdpi-v4/quantum_ic_grade_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_group_white_36.png | Bin .../res/drawable-hdpi-v4/quantum_ic_hd_white_24.png | Bin .../quantum_ic_headset_grey600_24.png | Bin .../quantum_ic_headset_white_36.png | Bin .../quantum_ic_history_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_image_white_24.png | Bin .../quantum_ic_info_outline_white_24.png | Bin .../quantum_ic_message_white_24.png | Bin .../quantum_ic_mic_off_black_24.png | Bin .../quantum_ic_mic_off_white_36.png | Bin .../quantum_ic_more_vert_white_24.png | Bin .../quantum_ic_network_wifi_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_pause_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_pause_white_36.png | Bin .../drawable-hdpi-v4/quantum_ic_people_white_24.png | Bin .../quantum_ic_person_add_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_person_white_24.png | Bin .../quantum_ic_photo_library_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_photo_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_photo_white_48.png | Bin .../quantum_ic_play_arrow_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_report_white_18.png | Bin .../drawable-hdpi-v4/quantum_ic_report_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_report_white_36.png | Bin .../quantum_ic_schedule_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_search_white_24.png | Bin .../drawable-hdpi-v4/quantum_ic_send_white_24.png | Bin .../quantum_ic_signal_wifi_4_bar_white_24.png | Bin .../quantum_ic_swap_calls_white_36.png | Bin .../drawable-hdpi-v4/quantum_ic_undo_white_48.png | Bin .../quantum_ic_videocam_off_white_24.png | Bin .../quantum_ic_videocam_off_white_36.png | Bin .../quantum_ic_videocam_white_18.png | Bin .../quantum_ic_videocam_white_24.png | Bin .../quantum_ic_videocam_white_36.png | Bin .../quantum_ic_voicemail_white_24.png | Bin .../quantum_ic_volume_down_white_24.png | Bin .../quantum_ic_volume_up_grey600_24.png | Bin .../quantum_ic_volume_up_white_24.png | Bin .../quantum_ic_volume_up_white_36.png | Bin .../quantum_ic_arrow_back_white_24.png | Bin .../quantum_ic_content_copy_grey600_24.png | Bin .../quantum_ic_send_white_24.png | Bin .../quantum_ic_undo_white_48.png | Bin .../quantum_ic_arrow_back_white_24.png | Bin .../quantum_ic_content_copy_grey600_24.png | Bin .../quantum_ic_send_white_24.png | Bin .../quantum_ic_undo_white_48.png | Bin .../quantum_ic_arrow_back_white_24.png | Bin .../quantum_ic_content_copy_grey600_24.png | Bin .../quantum_ic_send_white_24.png | Bin .../quantum_ic_undo_white_48.png | Bin .../quantum_ic_arrow_back_white_24.png | Bin .../quantum_ic_content_copy_grey600_24.png | Bin .../quantum_ic_send_white_24.png | Bin .../quantum_ic_undo_white_48.png | Bin .../quantum_ic_arrow_back_white_24.png | Bin .../quantum_ic_content_copy_grey600_24.png | Bin .../quantum_ic_send_white_24.png | Bin .../quantum_ic_undo_white_48.png | Bin .../quantum_ic_arrow_back_white_24.png | Bin .../quantum_ic_arrow_drop_down_white_18.png | Bin .../quantum_ic_backspace_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_block_white_24.png | Bin .../quantum_ic_bluetooth_audio_grey600_24.png | Bin .../quantum_ic_bluetooth_audio_white_36.png | Bin .../quantum_ic_call_end_white_24.png | Bin .../quantum_ic_call_end_white_36.png | Bin .../quantum_ic_call_made_white_24.png | Bin .../quantum_ic_call_merge_white_36.png | Bin .../quantum_ic_call_missed_white_24.png | Bin .../quantum_ic_call_received_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_call_white_18.png | Bin .../drawable-mdpi-v4/quantum_ic_call_white_24.png | Bin .../quantum_ic_camera_alt_white_24.png | Bin .../quantum_ic_camera_alt_white_48.png | Bin .../drawable-mdpi-v4/quantum_ic_check_black_24.png | Bin .../quantum_ic_check_circle_googblue_24.png | Bin .../drawable-mdpi-v4/quantum_ic_close_white_24.png | Bin .../quantum_ic_content_copy_grey600_24.png | Bin .../drawable-mdpi-v4/quantum_ic_delete_white_24.png | Bin .../quantum_ic_dialpad_white_24.png | Bin .../quantum_ic_dialpad_white_36.png | Bin .../drawable-mdpi-v4/quantum_ic_edit_grey600_24.png | Bin .../quantum_ic_forward_white_24.png | Bin .../quantum_ic_fullscreen_exit_white_48.png | Bin .../quantum_ic_fullscreen_white_48.png | Bin .../drawable-mdpi-v4/quantum_ic_grade_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_group_white_36.png | Bin .../res/drawable-mdpi-v4/quantum_ic_hd_white_24.png | Bin .../quantum_ic_headset_grey600_24.png | Bin .../quantum_ic_headset_white_36.png | Bin .../quantum_ic_history_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_image_white_24.png | Bin .../quantum_ic_info_outline_white_24.png | Bin .../quantum_ic_message_white_24.png | Bin .../quantum_ic_mic_off_black_24.png | Bin .../quantum_ic_mic_off_white_36.png | Bin .../quantum_ic_more_vert_white_24.png | Bin .../quantum_ic_network_wifi_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_pause_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_pause_white_36.png | Bin .../drawable-mdpi-v4/quantum_ic_people_white_24.png | Bin .../quantum_ic_person_add_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_person_white_24.png | Bin .../quantum_ic_photo_library_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_photo_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_photo_white_48.png | Bin .../quantum_ic_play_arrow_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_report_white_18.png | Bin .../drawable-mdpi-v4/quantum_ic_report_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_report_white_36.png | Bin .../quantum_ic_schedule_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_search_white_24.png | Bin .../drawable-mdpi-v4/quantum_ic_send_white_24.png | Bin .../quantum_ic_signal_wifi_4_bar_white_24.png | Bin .../quantum_ic_swap_calls_white_36.png | Bin .../drawable-mdpi-v4/quantum_ic_undo_white_48.png | Bin .../quantum_ic_videocam_off_white_24.png | Bin .../quantum_ic_videocam_off_white_36.png | Bin .../quantum_ic_videocam_white_18.png | Bin .../quantum_ic_videocam_white_24.png | Bin .../quantum_ic_videocam_white_36.png | Bin .../quantum_ic_voicemail_white_24.png | Bin .../quantum_ic_volume_down_white_24.png | Bin .../quantum_ic_volume_up_grey600_24.png | Bin .../quantum_ic_volume_up_white_24.png | Bin .../quantum_ic_volume_up_white_36.png | Bin .../src/main/res/drawable-v21/btn_dialpad_key.xml | 0 .../quantum_ic_arrow_back_white_24.png | Bin .../quantum_ic_arrow_drop_down_white_18.png | Bin .../quantum_ic_backspace_white_24.png | Bin .../drawable-xhdpi-v4/quantum_ic_block_white_24.png | Bin .../quantum_ic_bluetooth_audio_grey600_24.png | Bin .../quantum_ic_bluetooth_audio_white_36.png | Bin .../quantum_ic_call_end_white_24.png | Bin .../quantum_ic_call_end_white_36.png | Bin .../quantum_ic_call_made_white_24.png | Bin .../quantum_ic_call_merge_white_36.png | Bin .../quantum_ic_call_missed_white_24.png | Bin .../quantum_ic_call_received_white_24.png | Bin .../drawable-xhdpi-v4/quantum_ic_call_white_18.png | Bin .../drawable-xhdpi-v4/quantum_ic_call_white_24.png | Bin .../quantum_ic_camera_alt_white_24.png | Bin .../quantum_ic_camera_alt_white_48.png | Bin .../drawable-xhdpi-v4/quantum_ic_check_black_24.png | Bin .../quantum_ic_check_circle_googblue_24.png | Bin .../drawable-xhdpi-v4/quantum_ic_close_white_24.png | Bin .../quantum_ic_content_copy_grey600_24.png | Bin .../quantum_ic_delete_white_24.png | Bin .../quantum_ic_dialpad_white_24.png | Bin .../quantum_ic_dialpad_white_36.png | Bin .../quantum_ic_edit_grey600_24.png | Bin .../quantum_ic_forward_white_24.png | Bin .../quantum_ic_fullscreen_exit_white_48.png | Bin .../quantum_ic_fullscreen_white_48.png | Bin .../drawable-xhdpi-v4/quantum_ic_grade_white_24.png | Bin .../drawable-xhdpi-v4/quantum_ic_group_white_36.png | Bin .../drawable-xhdpi-v4/quantum_ic_hd_white_24.png | Bin .../quantum_ic_headset_grey600_24.png | Bin .../quantum_ic_headset_white_36.png | Bin .../quantum_ic_history_white_24.png | Bin .../drawable-xhdpi-v4/quantum_ic_image_white_24.png | Bin .../quantum_ic_info_outline_white_24.png | Bin .../quantum_ic_message_white_24.png | Bin .../quantum_ic_mic_off_black_24.png | Bin .../quantum_ic_mic_off_white_36.png | Bin .../quantum_ic_more_vert_white_24.png | Bin .../quantum_ic_network_wifi_white_24.png | Bin .../drawable-xhdpi-v4/quantum_ic_pause_white_24.png | Bin .../drawable-xhdpi-v4/quantum_ic_pause_white_36.png | Bin .../quantum_ic_people_white_24.png | Bin .../quantum_ic_person_add_white_24.png | Bin .../quantum_ic_person_white_24.png | Bin .../quantum_ic_photo_library_white_24.png | Bin .../drawable-xhdpi-v4/quantum_ic_photo_white_24.png | Bin .../drawable-xhdpi-v4/quantum_ic_photo_white_48.png | Bin .../quantum_ic_play_arrow_white_24.png | Bin .../quantum_ic_report_white_18.png | Bin .../quantum_ic_report_white_24.png | Bin .../quantum_ic_report_white_36.png | Bin .../quantum_ic_schedule_white_24.png | Bin .../quantum_ic_search_white_24.png | Bin .../drawable-xhdpi-v4/quantum_ic_send_white_24.png | Bin .../quantum_ic_signal_wifi_4_bar_white_24.png | Bin .../quantum_ic_swap_calls_white_36.png | Bin .../drawable-xhdpi-v4/quantum_ic_undo_white_48.png | Bin .../quantum_ic_videocam_off_white_24.png | Bin .../quantum_ic_videocam_off_white_36.png | Bin .../quantum_ic_videocam_white_18.png | Bin .../quantum_ic_videocam_white_24.png | Bin .../quantum_ic_videocam_white_36.png | Bin .../quantum_ic_voicemail_white_24.png | Bin .../quantum_ic_volume_down_white_24.png | Bin .../quantum_ic_volume_up_grey600_24.png | Bin .../quantum_ic_volume_up_white_24.png | Bin .../quantum_ic_volume_up_white_36.png | Bin .../quantum_ic_arrow_back_white_24.png | Bin .../quantum_ic_arrow_drop_down_white_18.png | Bin .../quantum_ic_backspace_white_24.png | Bin .../quantum_ic_block_white_24.png | Bin .../quantum_ic_bluetooth_audio_grey600_24.png | Bin .../quantum_ic_bluetooth_audio_white_36.png | Bin .../quantum_ic_call_end_white_24.png | Bin .../quantum_ic_call_end_white_36.png | Bin .../quantum_ic_call_made_white_24.png | Bin .../quantum_ic_call_merge_white_36.png | Bin .../quantum_ic_call_missed_white_24.png | Bin .../quantum_ic_call_received_white_24.png | Bin .../drawable-xxhdpi-v4/quantum_ic_call_white_18.png | Bin .../drawable-xxhdpi-v4/quantum_ic_call_white_24.png | Bin .../quantum_ic_camera_alt_white_24.png | Bin .../quantum_ic_camera_alt_white_48.png | Bin .../quantum_ic_check_black_24.png | Bin .../quantum_ic_check_circle_googblue_24.png | Bin .../quantum_ic_close_white_24.png | Bin .../quantum_ic_content_copy_grey600_24.png | Bin .../quantum_ic_delete_white_24.png | Bin .../quantum_ic_dialpad_white_24.png | Bin .../quantum_ic_dialpad_white_36.png | Bin .../quantum_ic_edit_grey600_24.png | Bin .../quantum_ic_forward_white_24.png | Bin .../quantum_ic_fullscreen_exit_white_48.png | Bin .../quantum_ic_fullscreen_white_48.png | Bin .../quantum_ic_grade_white_24.png | Bin .../quantum_ic_group_white_36.png | Bin .../drawable-xxhdpi-v4/quantum_ic_hd_white_24.png | Bin .../quantum_ic_headset_grey600_24.png | Bin .../quantum_ic_headset_white_36.png | Bin .../quantum_ic_history_white_24.png | Bin .../quantum_ic_image_white_24.png | Bin .../quantum_ic_info_outline_white_24.png | Bin .../quantum_ic_message_white_24.png | Bin .../quantum_ic_mic_off_black_24.png | Bin .../quantum_ic_mic_off_white_36.png | Bin .../quantum_ic_more_vert_white_24.png | Bin .../quantum_ic_network_wifi_white_24.png | Bin .../quantum_ic_pause_white_24.png | Bin .../quantum_ic_pause_white_36.png | Bin .../quantum_ic_people_white_24.png | Bin .../quantum_ic_person_add_white_24.png | Bin .../quantum_ic_person_white_24.png | Bin .../quantum_ic_photo_library_white_24.png | Bin .../quantum_ic_photo_white_24.png | Bin .../quantum_ic_photo_white_48.png | Bin .../quantum_ic_play_arrow_white_24.png | Bin .../quantum_ic_report_white_18.png | Bin .../quantum_ic_report_white_24.png | Bin .../quantum_ic_report_white_36.png | Bin .../quantum_ic_schedule_white_24.png | Bin .../quantum_ic_search_white_24.png | Bin .../drawable-xxhdpi-v4/quantum_ic_send_white_24.png | Bin .../quantum_ic_signal_wifi_4_bar_white_24.png | Bin .../quantum_ic_swap_calls_white_36.png | Bin .../drawable-xxhdpi-v4/quantum_ic_undo_white_48.png | Bin .../quantum_ic_videocam_off_white_24.png | Bin .../quantum_ic_videocam_off_white_36.png | Bin .../quantum_ic_videocam_white_18.png | Bin .../quantum_ic_videocam_white_24.png | Bin .../quantum_ic_videocam_white_36.png | Bin .../quantum_ic_voicemail_white_24.png | Bin .../quantum_ic_volume_down_white_24.png | Bin .../quantum_ic_volume_up_grey600_24.png | Bin .../quantum_ic_volume_up_white_24.png | Bin .../quantum_ic_volume_up_white_36.png | Bin .../quantum_ic_arrow_back_white_24.png | Bin .../quantum_ic_arrow_drop_down_white_18.png | Bin .../quantum_ic_backspace_white_24.png | Bin .../quantum_ic_block_white_24.png | Bin .../quantum_ic_bluetooth_audio_grey600_24.png | Bin .../quantum_ic_bluetooth_audio_white_36.png | Bin .../quantum_ic_call_end_white_24.png | Bin .../quantum_ic_call_end_white_36.png | Bin .../quantum_ic_call_made_white_24.png | Bin .../quantum_ic_call_merge_white_36.png | Bin .../quantum_ic_call_missed_white_24.png | Bin .../quantum_ic_call_received_white_24.png | Bin .../quantum_ic_call_white_18.png | Bin .../quantum_ic_call_white_24.png | Bin .../quantum_ic_camera_alt_white_24.png | Bin .../quantum_ic_camera_alt_white_48.png | Bin .../quantum_ic_check_black_24.png | Bin .../quantum_ic_check_circle_googblue_24.png | Bin .../quantum_ic_close_white_24.png | Bin .../quantum_ic_content_copy_grey600_24.png | Bin .../quantum_ic_delete_white_24.png | Bin .../quantum_ic_dialpad_white_24.png | Bin .../quantum_ic_dialpad_white_36.png | Bin .../quantum_ic_edit_grey600_24.png | Bin .../quantum_ic_forward_white_24.png | Bin .../quantum_ic_fullscreen_exit_white_48.png | Bin .../quantum_ic_fullscreen_white_48.png | Bin .../quantum_ic_grade_white_24.png | Bin .../quantum_ic_group_white_36.png | Bin .../drawable-xxxhdpi-v4/quantum_ic_hd_white_24.png | Bin .../quantum_ic_headset_grey600_24.png | Bin .../quantum_ic_headset_white_36.png | Bin .../quantum_ic_history_white_24.png | Bin .../quantum_ic_image_white_24.png | Bin .../quantum_ic_info_outline_white_24.png | Bin .../quantum_ic_message_white_24.png | Bin .../quantum_ic_mic_off_black_24.png | Bin .../quantum_ic_mic_off_white_36.png | Bin .../quantum_ic_more_vert_white_24.png | Bin .../quantum_ic_network_wifi_white_24.png | Bin .../quantum_ic_pause_white_24.png | Bin .../quantum_ic_pause_white_36.png | Bin .../quantum_ic_people_white_24.png | Bin .../quantum_ic_person_add_white_24.png | Bin .../quantum_ic_person_white_24.png | Bin .../quantum_ic_photo_library_white_24.png | Bin .../quantum_ic_photo_white_24.png | Bin .../quantum_ic_photo_white_48.png | Bin .../quantum_ic_play_arrow_white_24.png | Bin .../quantum_ic_report_white_18.png | Bin .../quantum_ic_report_white_24.png | Bin .../quantum_ic_report_white_36.png | Bin .../quantum_ic_schedule_white_24.png | Bin .../quantum_ic_search_white_24.png | Bin .../quantum_ic_send_white_24.png | Bin .../quantum_ic_signal_wifi_4_bar_white_24.png | Bin .../quantum_ic_swap_calls_white_36.png | Bin .../quantum_ic_undo_white_48.png | Bin .../quantum_ic_videocam_off_white_24.png | Bin .../quantum_ic_videocam_off_white_36.png | Bin .../quantum_ic_videocam_white_18.png | Bin .../quantum_ic_videocam_white_24.png | Bin .../quantum_ic_videocam_white_36.png | Bin .../quantum_ic_voicemail_white_24.png | Bin .../quantum_ic_volume_down_white_24.png | Bin .../quantum_ic_volume_up_grey600_24.png | Bin .../quantum_ic_volume_up_white_24.png | Bin .../quantum_ic_volume_up_white_36.png | Bin .../src/main/res/drawable/btn_dialpad_key.xml | 0 .../dialpad/src/main/res/layout/dialpad.xml | 0 .../src/main/res/layout/dialpad_fragment.xml | 0 .../dialpad/src/main/res/layout/dialpad_key.xml | 0 .../dialpad/src/main/res/layout/dialpad_key_one.xml | 0 .../src/main/res/layout/dialpad_key_pound.xml | 0 .../src/main/res/layout/dialpad_key_star.xml | 0 .../src/main/res/layout/dialpad_key_zero.xml | 0 .../dialpad/src/main/res/layout/dialpad_view.xml | 0 .../src/main/res/layout/dialpad_view_unthemed.xml | 0 .../dialpad/src/main/res/values-af/values-af.xml | 0 .../dialpad/src/main/res/values-am/values-am.xml | 0 .../dialpad/src/main/res/values-ar/values-ar.xml | 0 .../dialpad/src/main/res/values-az/values-az.xml | 0 .../main/res/values-b+sr+Latn/values-b+sr+Latn.xml | 0 .../dialpad/src/main/res/values-be/values-be.xml | 0 .../dialpad/src/main/res/values-bg/values-bg.xml | 0 .../dialpad/src/main/res/values-bn/values-bn.xml | 0 .../dialpad/src/main/res/values-bs/values-bs.xml | 0 .../dialpad/src/main/res/values-ca/values-ca.xml | 0 .../dialpad/src/main/res/values-cs/values-cs.xml | 0 .../dialpad/src/main/res/values-da/values-da.xml | 0 .../dialpad/src/main/res/values-de/values-de.xml | 0 .../dialpad/src/main/res/values-el/values-el.xml | 0 .../src/main/res/values-en-rAU/values-en-rAU.xml | 0 .../src/main/res/values-en-rGB/values-en-rGB.xml | 0 .../src/main/res/values-en-rIN/values-en-rIN.xml | 0 .../src/main/res/values-es-rUS/values-es-rUS.xml | 0 .../dialpad/src/main/res/values-es/values-es.xml | 0 .../dialpad/src/main/res/values-et/values-et.xml | 0 .../dialpad/src/main/res/values-eu/values-eu.xml | 0 .../dialpad/src/main/res/values-fa/values-fa.xml | 0 .../dialpad/src/main/res/values-fi/values-fi.xml | 0 .../src/main/res/values-fr-rCA/values-fr-rCA.xml | 0 .../dialpad/src/main/res/values-fr/values-fr.xml | 0 .../dialpad/src/main/res/values-gl/values-gl.xml | 0 .../dialpad/src/main/res/values-gu/values-gu.xml | 0 .../dialpad/src/main/res/values-hi/values-hi.xml | 0 .../dialpad/src/main/res/values-hr/values-hr.xml | 0 .../dialpad/src/main/res/values-hu/values-hu.xml | 0 .../dialpad/src/main/res/values-hy/values-hy.xml | 0 .../dialpad/src/main/res/values-in/values-in.xml | 0 .../dialpad/src/main/res/values-is/values-is.xml | 0 .../dialpad/src/main/res/values-it/values-it.xml | 0 .../dialpad/src/main/res/values-iw/values-iw.xml | 0 .../dialpad/src/main/res/values-ja/values-ja.xml | 0 .../dialpad/src/main/res/values-ka/values-ka.xml | 0 .../dialpad/src/main/res/values-kk/values-kk.xml | 0 .../dialpad/src/main/res/values-km/values-km.xml | 0 .../dialpad/src/main/res/values-kn/values-kn.xml | 0 .../dialpad/src/main/res/values-ko/values-ko.xml | 0 .../dialpad/src/main/res/values-ky/values-ky.xml | 0 .../src/main/res/values-land/values-land.xml | 0 .../dialpad/src/main/res/values-lo/values-lo.xml | 0 .../dialpad/src/main/res/values-lt/values-lt.xml | 0 .../dialpad/src/main/res/values-lv/values-lv.xml | 0 .../dialpad/src/main/res/values-mk/values-mk.xml | 0 .../dialpad/src/main/res/values-ml/values-ml.xml | 0 .../dialpad/src/main/res/values-mn/values-mn.xml | 0 .../dialpad/src/main/res/values-mr/values-mr.xml | 0 .../dialpad/src/main/res/values-ms/values-ms.xml | 0 .../dialpad/src/main/res/values-my/values-my.xml | 0 .../dialpad/src/main/res/values-nb/values-nb.xml | 0 .../dialpad/src/main/res/values-ne/values-ne.xml | 0 .../dialpad/src/main/res/values-nl/values-nl.xml | 0 .../dialpad/src/main/res/values-no/values-no.xml | 0 .../dialpad/src/main/res/values-pa/values-pa.xml | 0 .../dialpad/src/main/res/values-pl/values-pl.xml | 0 .../src/main/res/values-pt-rBR/values-pt-rBR.xml | 0 .../src/main/res/values-pt-rPT/values-pt-rPT.xml | 0 .../dialpad/src/main/res/values-pt/values-pt.xml | 0 .../dialpad/src/main/res/values-ro/values-ro.xml | 0 .../dialpad/src/main/res/values-ru/values-ru.xml | 0 .../dialpad/src/main/res/values-si/values-si.xml | 0 .../dialpad/src/main/res/values-sk/values-sk.xml | 0 .../dialpad/src/main/res/values-sl/values-sl.xml | 0 .../dialpad/src/main/res/values-sq/values-sq.xml | 0 .../dialpad/src/main/res/values-sr/values-sr.xml | 0 .../dialpad/src/main/res/values-sv/values-sv.xml | 0 .../dialpad/src/main/res/values-sw/values-sw.xml | 0 .../dialpad/src/main/res/values-ta/values-ta.xml | 0 .../dialpad/src/main/res/values-te/values-te.xml | 0 .../dialpad/src/main/res/values-th/values-th.xml | 0 .../dialpad/src/main/res/values-tl/values-tl.xml | 0 .../dialpad/src/main/res/values-tr/values-tr.xml | 0 .../dialpad/src/main/res/values-uk/values-uk.xml | 0 .../dialpad/src/main/res/values-ur/values-ur.xml | 0 .../dialpad/src/main/res/values-uz/values-uz.xml | 0 .../dialpad/src/main/res/values-vi/values-vi.xml | 0 .../src/main/res/values-zh-rCN/values-zh-rCN.xml | 0 .../src/main/res/values-zh-rHK/values-zh-rHK.xml | 0 .../src/main/res/values-zh-rTW/values-zh-rTW.xml | 0 .../dialpad/src/main/res/values-zu/values-zu.xml | 0 .../dialpad/src/main/res/values/values.xml | 0 library/{ => external}/diff-match-patch/.gitignore | 0 .../{ => external}/diff-match-patch/build.gradle | 0 .../fraser/neil/plaintext/diff_match_patch.java | 0 library/{ => external}/jsonviewer/.gitignore | 0 library/{ => external}/jsonviewer/build.gradle | 0 .../jsonviewer/src/main/AndroidManifest.xml | 0 .../org/billcarsonfr/jsonviewer/JSonViewerDialog.kt | 0 .../jsonviewer/JSonViewerEpoxyController.kt | 0 .../billcarsonfr/jsonviewer/JSonViewerFragment.kt | 0 .../org/billcarsonfr/jsonviewer/JSonViewerModel.kt | 0 .../jsonviewer/JSonViewerStyleProvider.kt | 0 .../billcarsonfr/jsonviewer/JSonViewerViewModel.kt | 0 .../main/java/org/billcarsonfr/jsonviewer/Utils.kt | 0 .../java/org/billcarsonfr/jsonviewer/ValueItem.kt | 0 .../src/main/res/layout/fragment_dialog_jv.xml | 0 .../main/res/layout/fragment_jv_recycler_view.xml | 0 .../res/layout/fragment_jv_recycler_view_wrap.xml | 0 .../src/main/res/layout/item_jv_base_value.xml | 0 .../jsonviewer/src/main/res/values/colors.xml | 0 .../jsonviewer/src/main/res/values/strings.xml | 0 .../org/billcarsonfr/jsonviewer/ModelParseTest.kt | 0 library/ui-styles/build.gradle | 2 +- settings.gradle | 11 +++++++---- vector/build.gradle | 6 +++--- 490 files changed, 12 insertions(+), 9 deletions(-) rename library/{ => external}/dialpad/build.gradle (100%) rename library/{ => external}/dialpad/src/main/AndroidManifest.xml (100%) rename library/{ => external}/dialpad/src/main/java/com/android/dialer/animation/AnimUtils.java (100%) rename library/{ => external}/dialpad/src/main/java/com/android/dialer/compat/PathInterpolatorCompat.java (100%) rename library/{ => external}/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadKeyButton.java (100%) rename library/{ => external}/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java (100%) rename library/{ => external}/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadView.java (100%) rename library/{ => external}/dialpad/src/main/java/com/android/dialer/dialpadview/DigitsEditText.java (100%) rename library/{ => external}/dialpad/src/main/java/com/android/dialer/util/ViewUtil.java (100%) rename library/{ => external}/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_back_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_drop_down_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_backspace_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_block_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_made_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_merge_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_missed_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_received_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_black_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_circle_googblue_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_close_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_content_copy_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_delete_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_edit_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_forward_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_fullscreen_exit_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_fullscreen_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_grade_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_group_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_hd_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_history_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_image_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_info_outline_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_message_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_black_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_more_vert_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_network_wifi_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_people_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_add_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_library_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_play_arrow_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_schedule_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_search_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_send_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_swap_calls_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_undo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_voicemail_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_down_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_arrow_back_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_content_copy_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_send_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_undo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_arrow_back_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_content_copy_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_send_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_undo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_arrow_back_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_content_copy_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_send_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_undo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_arrow_back_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_content_copy_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_send_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_undo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_arrow_back_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_content_copy_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_send_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_undo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_back_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_drop_down_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_backspace_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_block_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_made_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_merge_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_missed_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_received_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_black_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_circle_googblue_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_close_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_content_copy_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_delete_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_edit_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_forward_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_exit_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_grade_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_group_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_hd_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_history_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_image_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_info_outline_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_message_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_black_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_more_vert_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_network_wifi_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_people_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_person_add_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_person_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_library_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_play_arrow_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_schedule_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_search_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_send_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_swap_calls_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_undo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_voicemail_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_down_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-v21/btn_dialpad_key.xml (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_back_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_drop_down_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_backspace_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_block_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_made_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_merge_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_missed_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_received_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_check_black_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_check_circle_googblue_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_close_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_content_copy_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_delete_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_edit_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_forward_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_exit_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_grade_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_group_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_hd_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_history_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_image_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_info_outline_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_message_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_black_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_more_vert_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_network_wifi_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_people_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_add_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_library_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_play_arrow_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_schedule_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_search_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_send_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_swap_calls_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_undo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_voicemail_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_down_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_back_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_backspace_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_block_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_made_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_merge_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_missed_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_received_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_black_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_circle_googblue_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_close_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_content_copy_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_delete_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_dialpad_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_dialpad_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_edit_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_forward_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_grade_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_group_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_hd_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_headset_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_headset_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_history_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_image_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_info_outline_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_message_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_black_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_more_vert_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_network_wifi_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_people_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_add_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_library_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_play_arrow_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_schedule_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_search_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_send_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_swap_calls_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_undo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_off_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_off_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_voicemail_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_down_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_back_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_backspace_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_block_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_end_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_end_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_made_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_merge_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_missed_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_received_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_camera_alt_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_camera_alt_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_black_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_circle_googblue_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_close_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_content_copy_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_delete_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_edit_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_forward_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_grade_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_group_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_hd_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_history_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_image_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_info_outline_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_message_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_black_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_more_vert_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_network_wifi_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_people_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_add_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_library_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_play_arrow_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_schedule_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_search_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_send_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_swap_calls_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_undo_white_48.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_18.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_voicemail_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_down_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_grey600_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_24.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_36.png (100%) rename library/{ => external}/dialpad/src/main/res/drawable/btn_dialpad_key.xml (100%) rename library/{ => external}/dialpad/src/main/res/layout/dialpad.xml (100%) rename library/{ => external}/dialpad/src/main/res/layout/dialpad_fragment.xml (100%) rename library/{ => external}/dialpad/src/main/res/layout/dialpad_key.xml (100%) rename library/{ => external}/dialpad/src/main/res/layout/dialpad_key_one.xml (100%) rename library/{ => external}/dialpad/src/main/res/layout/dialpad_key_pound.xml (100%) rename library/{ => external}/dialpad/src/main/res/layout/dialpad_key_star.xml (100%) rename library/{ => external}/dialpad/src/main/res/layout/dialpad_key_zero.xml (100%) rename library/{ => external}/dialpad/src/main/res/layout/dialpad_view.xml (100%) rename library/{ => external}/dialpad/src/main/res/layout/dialpad_view_unthemed.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-af/values-af.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-am/values-am.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ar/values-ar.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-az/values-az.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-b+sr+Latn/values-b+sr+Latn.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-be/values-be.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-bg/values-bg.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-bn/values-bn.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-bs/values-bs.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ca/values-ca.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-cs/values-cs.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-da/values-da.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-de/values-de.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-el/values-el.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-en-rAU/values-en-rAU.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-en-rGB/values-en-rGB.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-en-rIN/values-en-rIN.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-es-rUS/values-es-rUS.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-es/values-es.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-et/values-et.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-eu/values-eu.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-fa/values-fa.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-fi/values-fi.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-fr-rCA/values-fr-rCA.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-fr/values-fr.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-gl/values-gl.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-gu/values-gu.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-hi/values-hi.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-hr/values-hr.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-hu/values-hu.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-hy/values-hy.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-in/values-in.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-is/values-is.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-it/values-it.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-iw/values-iw.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ja/values-ja.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ka/values-ka.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-kk/values-kk.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-km/values-km.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-kn/values-kn.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ko/values-ko.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ky/values-ky.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-land/values-land.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-lo/values-lo.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-lt/values-lt.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-lv/values-lv.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-mk/values-mk.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ml/values-ml.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-mn/values-mn.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-mr/values-mr.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ms/values-ms.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-my/values-my.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-nb/values-nb.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ne/values-ne.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-nl/values-nl.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-no/values-no.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-pa/values-pa.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-pl/values-pl.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-pt-rBR/values-pt-rBR.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-pt-rPT/values-pt-rPT.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-pt/values-pt.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ro/values-ro.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ru/values-ru.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-si/values-si.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-sk/values-sk.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-sl/values-sl.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-sq/values-sq.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-sr/values-sr.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-sv/values-sv.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-sw/values-sw.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ta/values-ta.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-te/values-te.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-th/values-th.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-tl/values-tl.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-tr/values-tr.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-uk/values-uk.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-ur/values-ur.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-uz/values-uz.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-vi/values-vi.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-zh-rCN/values-zh-rCN.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-zh-rHK/values-zh-rHK.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-zh-rTW/values-zh-rTW.xml (100%) rename library/{ => external}/dialpad/src/main/res/values-zu/values-zu.xml (100%) rename library/{ => external}/dialpad/src/main/res/values/values.xml (100%) rename library/{ => external}/diff-match-patch/.gitignore (100%) rename library/{ => external}/diff-match-patch/build.gradle (100%) rename library/{ => external}/diff-match-patch/src/main/java/name/fraser/neil/plaintext/diff_match_patch.java (100%) rename library/{ => external}/jsonviewer/.gitignore (100%) rename library/{ => external}/jsonviewer/build.gradle (100%) rename library/{ => external}/jsonviewer/src/main/AndroidManifest.xml (100%) rename library/{ => external}/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerDialog.kt (100%) rename library/{ => external}/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerEpoxyController.kt (100%) rename library/{ => external}/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerFragment.kt (100%) rename library/{ => external}/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerModel.kt (100%) rename library/{ => external}/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerStyleProvider.kt (100%) rename library/{ => external}/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerViewModel.kt (100%) rename library/{ => external}/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/Utils.kt (100%) rename library/{ => external}/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/ValueItem.kt (100%) rename library/{ => external}/jsonviewer/src/main/res/layout/fragment_dialog_jv.xml (100%) rename library/{ => external}/jsonviewer/src/main/res/layout/fragment_jv_recycler_view.xml (100%) rename library/{ => external}/jsonviewer/src/main/res/layout/fragment_jv_recycler_view_wrap.xml (100%) rename library/{ => external}/jsonviewer/src/main/res/layout/item_jv_base_value.xml (100%) rename library/{ => external}/jsonviewer/src/main/res/values/colors.xml (100%) rename library/{ => external}/jsonviewer/src/main/res/values/strings.xml (100%) rename library/{ => external}/jsonviewer/src/test/java/org/billcarsonfr/jsonviewer/ModelParseTest.kt (100%) diff --git a/build.gradle b/build.gradle index a40790d441..7db1db88b4 100644 --- a/build.gradle +++ b/build.gradle @@ -216,7 +216,7 @@ project(":vector") { } } -project(":library:diff-match-patch") { +project(":library:external:diff-match-patch") { sonarqube { skipProject = true } diff --git a/library/dialpad/build.gradle b/library/external/dialpad/build.gradle similarity index 100% rename from library/dialpad/build.gradle rename to library/external/dialpad/build.gradle diff --git a/library/dialpad/src/main/AndroidManifest.xml b/library/external/dialpad/src/main/AndroidManifest.xml similarity index 100% rename from library/dialpad/src/main/AndroidManifest.xml rename to library/external/dialpad/src/main/AndroidManifest.xml diff --git a/library/dialpad/src/main/java/com/android/dialer/animation/AnimUtils.java b/library/external/dialpad/src/main/java/com/android/dialer/animation/AnimUtils.java similarity index 100% rename from library/dialpad/src/main/java/com/android/dialer/animation/AnimUtils.java rename to library/external/dialpad/src/main/java/com/android/dialer/animation/AnimUtils.java diff --git a/library/dialpad/src/main/java/com/android/dialer/compat/PathInterpolatorCompat.java b/library/external/dialpad/src/main/java/com/android/dialer/compat/PathInterpolatorCompat.java similarity index 100% rename from library/dialpad/src/main/java/com/android/dialer/compat/PathInterpolatorCompat.java rename to library/external/dialpad/src/main/java/com/android/dialer/compat/PathInterpolatorCompat.java diff --git a/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadKeyButton.java b/library/external/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadKeyButton.java similarity index 100% rename from library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadKeyButton.java rename to library/external/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadKeyButton.java diff --git a/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java b/library/external/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java similarity index 100% rename from library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java rename to library/external/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadTextView.java diff --git a/library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadView.java b/library/external/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadView.java similarity index 100% rename from library/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadView.java rename to library/external/dialpad/src/main/java/com/android/dialer/dialpadview/DialpadView.java diff --git a/library/dialpad/src/main/java/com/android/dialer/dialpadview/DigitsEditText.java b/library/external/dialpad/src/main/java/com/android/dialer/dialpadview/DigitsEditText.java similarity index 100% rename from library/dialpad/src/main/java/com/android/dialer/dialpadview/DigitsEditText.java rename to library/external/dialpad/src/main/java/com/android/dialer/dialpadview/DigitsEditText.java diff --git a/library/dialpad/src/main/java/com/android/dialer/util/ViewUtil.java b/library/external/dialpad/src/main/java/com/android/dialer/util/ViewUtil.java similarity index 100% rename from library/dialpad/src/main/java/com/android/dialer/util/ViewUtil.java rename to library/external/dialpad/src/main/java/com/android/dialer/util/ViewUtil.java diff --git a/library/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java b/library/external/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java similarity index 100% rename from library/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java rename to library/external/dialpad/src/main/java/com/android/dialer/widget/ResizingTextEditText.java diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_back_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_back_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_back_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_back_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_drop_down_white_18.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_drop_down_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_drop_down_white_18.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_arrow_drop_down_white_18.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_backspace_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_backspace_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_backspace_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_backspace_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_block_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_block_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_block_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_block_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_bluetooth_audio_white_36.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_end_white_36.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_made_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_made_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_made_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_made_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_merge_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_merge_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_merge_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_merge_white_36.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_missed_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_missed_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_missed_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_missed_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_received_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_received_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_received_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_received_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_white_18.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_white_18.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_white_18.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_call_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_48.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_48.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_camera_alt_white_48.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_black_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_black_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_black_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_black_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_circle_googblue_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_circle_googblue_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_circle_googblue_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_check_circle_googblue_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_close_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_close_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_close_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_close_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_content_copy_grey600_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_content_copy_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_content_copy_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_content_copy_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_delete_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_delete_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_delete_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_delete_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_dialpad_white_36.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_edit_grey600_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_edit_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_edit_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_edit_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_forward_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_forward_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_forward_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_forward_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_fullscreen_exit_white_48.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_fullscreen_exit_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_fullscreen_exit_white_48.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_fullscreen_exit_white_48.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_fullscreen_white_48.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_fullscreen_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_fullscreen_white_48.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_fullscreen_white_48.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_grade_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_grade_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_grade_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_grade_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_group_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_group_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_group_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_group_white_36.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_hd_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_hd_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_hd_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_hd_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_grey600_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_headset_white_36.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_history_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_history_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_history_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_history_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_image_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_image_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_image_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_image_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_info_outline_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_info_outline_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_info_outline_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_info_outline_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_message_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_message_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_message_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_message_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_black_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_black_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_black_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_black_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_mic_off_white_36.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_more_vert_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_more_vert_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_more_vert_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_more_vert_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_network_wifi_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_network_wifi_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_network_wifi_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_network_wifi_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_pause_white_36.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_people_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_people_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_people_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_people_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_add_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_add_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_add_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_add_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_person_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_library_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_library_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_library_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_library_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_48.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_48.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_photo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_play_arrow_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_play_arrow_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_play_arrow_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_play_arrow_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_18.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_18.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_18.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_report_white_36.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_schedule_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_schedule_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_schedule_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_schedule_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_search_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_search_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_search_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_search_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_send_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_send_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_send_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_send_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_swap_calls_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_swap_calls_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_swap_calls_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_swap_calls_white_36.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_undo_white_48.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_undo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_undo_white_48.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_undo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_off_white_36.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_18.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_18.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_18.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_videocam_white_36.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_voicemail_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_voicemail_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_voicemail_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_voicemail_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_down_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_down_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_down_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_down_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_grey600_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_white_24.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_white_24.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_white_24.png diff --git a/library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_white_36.png b/library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_white_36.png rename to library/external/dialpad/src/main/res/drawable-hdpi-v4/quantum_ic_volume_up_white_36.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_arrow_back_white_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_arrow_back_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_arrow_back_white_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_arrow_back_white_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_content_copy_grey600_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_content_copy_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_content_copy_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_content_copy_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_send_white_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_send_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_send_white_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_send_white_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_undo_white_48.png b/library/external/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_undo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_undo_white_48.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-hdpi-v17/quantum_ic_undo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_arrow_back_white_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_arrow_back_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_arrow_back_white_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_arrow_back_white_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_content_copy_grey600_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_content_copy_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_content_copy_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_content_copy_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_send_white_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_send_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_send_white_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_send_white_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_undo_white_48.png b/library/external/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_undo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_undo_white_48.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-mdpi-v17/quantum_ic_undo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_arrow_back_white_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_arrow_back_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_arrow_back_white_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_arrow_back_white_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_content_copy_grey600_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_content_copy_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_content_copy_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_content_copy_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_send_white_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_send_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_send_white_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_send_white_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_undo_white_48.png b/library/external/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_undo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_undo_white_48.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-xhdpi-v17/quantum_ic_undo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_arrow_back_white_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_arrow_back_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_arrow_back_white_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_arrow_back_white_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_content_copy_grey600_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_content_copy_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_content_copy_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_content_copy_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_send_white_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_send_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_send_white_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_send_white_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_undo_white_48.png b/library/external/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_undo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_undo_white_48.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-xxhdpi-v17/quantum_ic_undo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_arrow_back_white_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_arrow_back_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_arrow_back_white_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_arrow_back_white_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_content_copy_grey600_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_content_copy_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_content_copy_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_content_copy_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_send_white_24.png b/library/external/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_send_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_send_white_24.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_send_white_24.png diff --git a/library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_undo_white_48.png b/library/external/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_undo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_undo_white_48.png rename to library/external/dialpad/src/main/res/drawable-ldrtl-xxxhdpi-v17/quantum_ic_undo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_back_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_back_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_back_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_back_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_drop_down_white_18.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_drop_down_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_drop_down_white_18.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_arrow_drop_down_white_18.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_backspace_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_backspace_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_backspace_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_backspace_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_block_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_block_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_block_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_block_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_bluetooth_audio_white_36.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_end_white_36.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_made_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_made_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_made_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_made_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_merge_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_merge_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_merge_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_merge_white_36.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_missed_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_missed_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_missed_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_missed_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_received_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_received_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_received_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_received_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_white_18.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_white_18.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_white_18.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_call_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_48.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_48.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_camera_alt_white_48.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_black_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_black_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_black_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_black_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_circle_googblue_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_circle_googblue_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_circle_googblue_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_check_circle_googblue_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_close_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_close_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_close_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_close_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_content_copy_grey600_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_content_copy_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_content_copy_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_content_copy_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_delete_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_delete_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_delete_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_delete_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_dialpad_white_36.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_edit_grey600_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_edit_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_edit_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_edit_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_forward_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_forward_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_forward_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_forward_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_exit_white_48.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_exit_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_exit_white_48.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_exit_white_48.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_white_48.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_white_48.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_fullscreen_white_48.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_grade_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_grade_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_grade_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_grade_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_group_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_group_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_group_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_group_white_36.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_hd_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_hd_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_hd_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_hd_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_grey600_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_headset_white_36.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_history_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_history_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_history_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_history_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_image_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_image_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_image_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_image_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_info_outline_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_info_outline_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_info_outline_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_info_outline_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_message_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_message_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_message_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_message_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_black_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_black_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_black_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_black_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_mic_off_white_36.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_more_vert_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_more_vert_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_more_vert_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_more_vert_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_network_wifi_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_network_wifi_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_network_wifi_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_network_wifi_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_pause_white_36.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_people_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_people_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_people_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_people_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_person_add_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_person_add_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_person_add_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_person_add_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_person_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_person_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_person_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_person_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_library_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_library_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_library_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_library_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_48.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_48.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_photo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_play_arrow_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_play_arrow_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_play_arrow_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_play_arrow_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_18.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_18.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_18.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_report_white_36.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_schedule_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_schedule_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_schedule_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_schedule_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_search_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_search_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_search_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_search_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_send_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_send_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_send_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_send_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_swap_calls_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_swap_calls_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_swap_calls_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_swap_calls_white_36.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_undo_white_48.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_undo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_undo_white_48.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_undo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_off_white_36.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_18.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_18.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_18.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_videocam_white_36.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_voicemail_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_voicemail_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_voicemail_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_voicemail_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_down_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_down_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_down_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_down_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_grey600_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_white_24.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_white_24.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_white_24.png diff --git a/library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_white_36.png b/library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_white_36.png rename to library/external/dialpad/src/main/res/drawable-mdpi-v4/quantum_ic_volume_up_white_36.png diff --git a/library/dialpad/src/main/res/drawable-v21/btn_dialpad_key.xml b/library/external/dialpad/src/main/res/drawable-v21/btn_dialpad_key.xml similarity index 100% rename from library/dialpad/src/main/res/drawable-v21/btn_dialpad_key.xml rename to library/external/dialpad/src/main/res/drawable-v21/btn_dialpad_key.xml diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_back_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_back_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_back_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_back_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_drop_down_white_18.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_drop_down_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_drop_down_white_18.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_arrow_drop_down_white_18.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_backspace_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_backspace_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_backspace_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_backspace_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_block_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_block_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_block_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_block_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_bluetooth_audio_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_end_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_made_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_made_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_made_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_made_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_merge_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_merge_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_merge_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_merge_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_missed_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_missed_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_missed_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_missed_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_received_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_received_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_received_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_received_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_white_18.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_white_18.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_white_18.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_call_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_48.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_48.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_camera_alt_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_check_black_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_check_black_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_check_black_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_check_black_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_check_circle_googblue_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_check_circle_googblue_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_check_circle_googblue_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_check_circle_googblue_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_close_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_close_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_close_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_close_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_content_copy_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_content_copy_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_content_copy_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_content_copy_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_delete_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_delete_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_delete_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_delete_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_dialpad_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_edit_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_edit_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_edit_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_edit_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_forward_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_forward_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_forward_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_forward_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_exit_white_48.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_exit_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_exit_white_48.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_exit_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_white_48.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_white_48.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_fullscreen_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_grade_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_grade_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_grade_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_grade_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_group_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_group_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_group_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_group_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_hd_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_hd_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_hd_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_hd_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_headset_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_history_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_history_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_history_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_history_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_image_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_image_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_image_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_image_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_info_outline_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_info_outline_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_info_outline_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_info_outline_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_message_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_message_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_message_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_message_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_black_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_black_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_black_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_black_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_mic_off_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_more_vert_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_more_vert_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_more_vert_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_more_vert_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_network_wifi_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_network_wifi_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_network_wifi_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_network_wifi_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_pause_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_people_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_people_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_people_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_people_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_add_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_add_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_add_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_add_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_person_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_library_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_library_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_library_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_library_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_48.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_48.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_photo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_play_arrow_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_play_arrow_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_play_arrow_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_play_arrow_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_18.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_18.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_18.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_report_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_schedule_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_schedule_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_schedule_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_schedule_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_search_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_search_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_search_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_search_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_send_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_send_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_send_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_send_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_swap_calls_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_swap_calls_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_swap_calls_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_swap_calls_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_undo_white_48.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_undo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_undo_white_48.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_undo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_off_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_18.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_18.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_18.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_videocam_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_voicemail_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_voicemail_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_voicemail_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_voicemail_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_down_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_down_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_down_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_down_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_24.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_24.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_36.png b/library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_36.png rename to library/external/dialpad/src/main/res/drawable-xhdpi-v4/quantum_ic_volume_up_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_back_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_back_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_back_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_back_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_backspace_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_backspace_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_backspace_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_backspace_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_block_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_block_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_block_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_block_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_end_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_made_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_made_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_made_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_made_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_merge_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_merge_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_merge_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_merge_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_missed_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_missed_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_missed_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_missed_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_received_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_received_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_received_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_received_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_18.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_18.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_18.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_call_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_48.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_48.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_camera_alt_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_black_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_black_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_black_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_black_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_circle_googblue_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_circle_googblue_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_circle_googblue_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_check_circle_googblue_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_close_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_close_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_close_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_close_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_content_copy_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_content_copy_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_content_copy_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_content_copy_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_delete_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_delete_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_delete_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_delete_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_dialpad_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_dialpad_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_dialpad_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_dialpad_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_dialpad_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_dialpad_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_dialpad_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_dialpad_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_edit_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_edit_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_edit_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_edit_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_forward_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_forward_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_forward_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_forward_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_white_48.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_white_48.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_fullscreen_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_grade_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_grade_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_grade_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_grade_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_group_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_group_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_group_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_group_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_hd_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_hd_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_hd_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_hd_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_headset_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_headset_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_headset_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_headset_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_headset_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_headset_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_headset_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_headset_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_history_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_history_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_history_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_history_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_image_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_image_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_image_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_image_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_info_outline_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_info_outline_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_info_outline_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_info_outline_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_message_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_message_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_message_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_message_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_black_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_black_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_black_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_black_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_mic_off_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_more_vert_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_more_vert_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_more_vert_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_more_vert_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_network_wifi_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_network_wifi_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_network_wifi_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_network_wifi_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_pause_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_people_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_people_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_people_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_people_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_add_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_add_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_add_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_add_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_person_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_library_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_library_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_library_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_library_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_48.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_48.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_photo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_play_arrow_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_play_arrow_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_play_arrow_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_play_arrow_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_18.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_18.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_18.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_report_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_schedule_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_schedule_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_schedule_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_schedule_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_search_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_search_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_search_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_search_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_send_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_send_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_send_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_send_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_swap_calls_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_swap_calls_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_swap_calls_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_swap_calls_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_undo_white_48.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_undo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_undo_white_48.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_undo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_off_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_off_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_off_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_off_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_off_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_off_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_off_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_off_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_18.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_18.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_18.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_videocam_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_voicemail_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_voicemail_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_voicemail_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_voicemail_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_down_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_down_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_down_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_down_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_24.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_36.png b/library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxhdpi-v4/quantum_ic_volume_up_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_back_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_back_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_back_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_back_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_arrow_drop_down_white_18.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_backspace_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_backspace_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_backspace_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_backspace_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_block_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_block_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_block_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_block_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_bluetooth_audio_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_bluetooth_audio_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_end_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_end_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_end_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_end_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_end_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_end_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_end_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_end_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_made_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_made_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_made_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_made_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_merge_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_merge_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_merge_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_merge_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_missed_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_missed_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_missed_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_missed_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_received_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_received_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_received_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_received_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_18.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_18.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_18.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_call_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_camera_alt_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_camera_alt_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_camera_alt_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_camera_alt_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_camera_alt_white_48.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_camera_alt_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_camera_alt_white_48.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_camera_alt_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_black_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_black_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_black_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_black_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_circle_googblue_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_circle_googblue_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_circle_googblue_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_check_circle_googblue_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_close_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_close_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_close_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_close_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_content_copy_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_content_copy_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_content_copy_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_content_copy_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_delete_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_delete_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_delete_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_delete_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_dialpad_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_edit_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_edit_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_edit_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_edit_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_forward_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_forward_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_forward_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_forward_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_exit_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_white_48.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_white_48.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_fullscreen_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_grade_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_grade_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_grade_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_grade_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_group_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_group_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_group_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_group_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_hd_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_hd_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_hd_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_hd_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_headset_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_history_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_history_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_history_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_history_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_image_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_image_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_image_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_image_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_info_outline_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_info_outline_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_info_outline_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_info_outline_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_message_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_message_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_message_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_message_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_black_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_black_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_black_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_black_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_mic_off_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_more_vert_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_more_vert_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_more_vert_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_more_vert_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_network_wifi_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_network_wifi_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_network_wifi_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_network_wifi_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_pause_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_people_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_people_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_people_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_people_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_add_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_add_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_add_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_add_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_person_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_library_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_library_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_library_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_library_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_white_48.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_white_48.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_photo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_play_arrow_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_play_arrow_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_play_arrow_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_play_arrow_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_18.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_18.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_18.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_report_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_schedule_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_schedule_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_schedule_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_schedule_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_search_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_search_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_search_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_search_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_send_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_send_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_send_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_send_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_signal_wifi_4_bar_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_swap_calls_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_swap_calls_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_swap_calls_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_swap_calls_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_undo_white_48.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_undo_white_48.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_undo_white_48.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_undo_white_48.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_off_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_18.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_18.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_18.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_18.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_videocam_white_36.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_voicemail_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_voicemail_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_voicemail_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_voicemail_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_down_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_down_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_down_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_down_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_grey600_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_grey600_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_grey600_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_grey600_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_24.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_24.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_24.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_24.png diff --git a/library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_36.png b/library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_36.png similarity index 100% rename from library/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_36.png rename to library/external/dialpad/src/main/res/drawable-xxxhdpi-v4/quantum_ic_volume_up_white_36.png diff --git a/library/dialpad/src/main/res/drawable/btn_dialpad_key.xml b/library/external/dialpad/src/main/res/drawable/btn_dialpad_key.xml similarity index 100% rename from library/dialpad/src/main/res/drawable/btn_dialpad_key.xml rename to library/external/dialpad/src/main/res/drawable/btn_dialpad_key.xml diff --git a/library/dialpad/src/main/res/layout/dialpad.xml b/library/external/dialpad/src/main/res/layout/dialpad.xml similarity index 100% rename from library/dialpad/src/main/res/layout/dialpad.xml rename to library/external/dialpad/src/main/res/layout/dialpad.xml diff --git a/library/dialpad/src/main/res/layout/dialpad_fragment.xml b/library/external/dialpad/src/main/res/layout/dialpad_fragment.xml similarity index 100% rename from library/dialpad/src/main/res/layout/dialpad_fragment.xml rename to library/external/dialpad/src/main/res/layout/dialpad_fragment.xml diff --git a/library/dialpad/src/main/res/layout/dialpad_key.xml b/library/external/dialpad/src/main/res/layout/dialpad_key.xml similarity index 100% rename from library/dialpad/src/main/res/layout/dialpad_key.xml rename to library/external/dialpad/src/main/res/layout/dialpad_key.xml diff --git a/library/dialpad/src/main/res/layout/dialpad_key_one.xml b/library/external/dialpad/src/main/res/layout/dialpad_key_one.xml similarity index 100% rename from library/dialpad/src/main/res/layout/dialpad_key_one.xml rename to library/external/dialpad/src/main/res/layout/dialpad_key_one.xml diff --git a/library/dialpad/src/main/res/layout/dialpad_key_pound.xml b/library/external/dialpad/src/main/res/layout/dialpad_key_pound.xml similarity index 100% rename from library/dialpad/src/main/res/layout/dialpad_key_pound.xml rename to library/external/dialpad/src/main/res/layout/dialpad_key_pound.xml diff --git a/library/dialpad/src/main/res/layout/dialpad_key_star.xml b/library/external/dialpad/src/main/res/layout/dialpad_key_star.xml similarity index 100% rename from library/dialpad/src/main/res/layout/dialpad_key_star.xml rename to library/external/dialpad/src/main/res/layout/dialpad_key_star.xml diff --git a/library/dialpad/src/main/res/layout/dialpad_key_zero.xml b/library/external/dialpad/src/main/res/layout/dialpad_key_zero.xml similarity index 100% rename from library/dialpad/src/main/res/layout/dialpad_key_zero.xml rename to library/external/dialpad/src/main/res/layout/dialpad_key_zero.xml diff --git a/library/dialpad/src/main/res/layout/dialpad_view.xml b/library/external/dialpad/src/main/res/layout/dialpad_view.xml similarity index 100% rename from library/dialpad/src/main/res/layout/dialpad_view.xml rename to library/external/dialpad/src/main/res/layout/dialpad_view.xml diff --git a/library/dialpad/src/main/res/layout/dialpad_view_unthemed.xml b/library/external/dialpad/src/main/res/layout/dialpad_view_unthemed.xml similarity index 100% rename from library/dialpad/src/main/res/layout/dialpad_view_unthemed.xml rename to library/external/dialpad/src/main/res/layout/dialpad_view_unthemed.xml diff --git a/library/dialpad/src/main/res/values-af/values-af.xml b/library/external/dialpad/src/main/res/values-af/values-af.xml similarity index 100% rename from library/dialpad/src/main/res/values-af/values-af.xml rename to library/external/dialpad/src/main/res/values-af/values-af.xml diff --git a/library/dialpad/src/main/res/values-am/values-am.xml b/library/external/dialpad/src/main/res/values-am/values-am.xml similarity index 100% rename from library/dialpad/src/main/res/values-am/values-am.xml rename to library/external/dialpad/src/main/res/values-am/values-am.xml diff --git a/library/dialpad/src/main/res/values-ar/values-ar.xml b/library/external/dialpad/src/main/res/values-ar/values-ar.xml similarity index 100% rename from library/dialpad/src/main/res/values-ar/values-ar.xml rename to library/external/dialpad/src/main/res/values-ar/values-ar.xml diff --git a/library/dialpad/src/main/res/values-az/values-az.xml b/library/external/dialpad/src/main/res/values-az/values-az.xml similarity index 100% rename from library/dialpad/src/main/res/values-az/values-az.xml rename to library/external/dialpad/src/main/res/values-az/values-az.xml diff --git a/library/dialpad/src/main/res/values-b+sr+Latn/values-b+sr+Latn.xml b/library/external/dialpad/src/main/res/values-b+sr+Latn/values-b+sr+Latn.xml similarity index 100% rename from library/dialpad/src/main/res/values-b+sr+Latn/values-b+sr+Latn.xml rename to library/external/dialpad/src/main/res/values-b+sr+Latn/values-b+sr+Latn.xml diff --git a/library/dialpad/src/main/res/values-be/values-be.xml b/library/external/dialpad/src/main/res/values-be/values-be.xml similarity index 100% rename from library/dialpad/src/main/res/values-be/values-be.xml rename to library/external/dialpad/src/main/res/values-be/values-be.xml diff --git a/library/dialpad/src/main/res/values-bg/values-bg.xml b/library/external/dialpad/src/main/res/values-bg/values-bg.xml similarity index 100% rename from library/dialpad/src/main/res/values-bg/values-bg.xml rename to library/external/dialpad/src/main/res/values-bg/values-bg.xml diff --git a/library/dialpad/src/main/res/values-bn/values-bn.xml b/library/external/dialpad/src/main/res/values-bn/values-bn.xml similarity index 100% rename from library/dialpad/src/main/res/values-bn/values-bn.xml rename to library/external/dialpad/src/main/res/values-bn/values-bn.xml diff --git a/library/dialpad/src/main/res/values-bs/values-bs.xml b/library/external/dialpad/src/main/res/values-bs/values-bs.xml similarity index 100% rename from library/dialpad/src/main/res/values-bs/values-bs.xml rename to library/external/dialpad/src/main/res/values-bs/values-bs.xml diff --git a/library/dialpad/src/main/res/values-ca/values-ca.xml b/library/external/dialpad/src/main/res/values-ca/values-ca.xml similarity index 100% rename from library/dialpad/src/main/res/values-ca/values-ca.xml rename to library/external/dialpad/src/main/res/values-ca/values-ca.xml diff --git a/library/dialpad/src/main/res/values-cs/values-cs.xml b/library/external/dialpad/src/main/res/values-cs/values-cs.xml similarity index 100% rename from library/dialpad/src/main/res/values-cs/values-cs.xml rename to library/external/dialpad/src/main/res/values-cs/values-cs.xml diff --git a/library/dialpad/src/main/res/values-da/values-da.xml b/library/external/dialpad/src/main/res/values-da/values-da.xml similarity index 100% rename from library/dialpad/src/main/res/values-da/values-da.xml rename to library/external/dialpad/src/main/res/values-da/values-da.xml diff --git a/library/dialpad/src/main/res/values-de/values-de.xml b/library/external/dialpad/src/main/res/values-de/values-de.xml similarity index 100% rename from library/dialpad/src/main/res/values-de/values-de.xml rename to library/external/dialpad/src/main/res/values-de/values-de.xml diff --git a/library/dialpad/src/main/res/values-el/values-el.xml b/library/external/dialpad/src/main/res/values-el/values-el.xml similarity index 100% rename from library/dialpad/src/main/res/values-el/values-el.xml rename to library/external/dialpad/src/main/res/values-el/values-el.xml diff --git a/library/dialpad/src/main/res/values-en-rAU/values-en-rAU.xml b/library/external/dialpad/src/main/res/values-en-rAU/values-en-rAU.xml similarity index 100% rename from library/dialpad/src/main/res/values-en-rAU/values-en-rAU.xml rename to library/external/dialpad/src/main/res/values-en-rAU/values-en-rAU.xml diff --git a/library/dialpad/src/main/res/values-en-rGB/values-en-rGB.xml b/library/external/dialpad/src/main/res/values-en-rGB/values-en-rGB.xml similarity index 100% rename from library/dialpad/src/main/res/values-en-rGB/values-en-rGB.xml rename to library/external/dialpad/src/main/res/values-en-rGB/values-en-rGB.xml diff --git a/library/dialpad/src/main/res/values-en-rIN/values-en-rIN.xml b/library/external/dialpad/src/main/res/values-en-rIN/values-en-rIN.xml similarity index 100% rename from library/dialpad/src/main/res/values-en-rIN/values-en-rIN.xml rename to library/external/dialpad/src/main/res/values-en-rIN/values-en-rIN.xml diff --git a/library/dialpad/src/main/res/values-es-rUS/values-es-rUS.xml b/library/external/dialpad/src/main/res/values-es-rUS/values-es-rUS.xml similarity index 100% rename from library/dialpad/src/main/res/values-es-rUS/values-es-rUS.xml rename to library/external/dialpad/src/main/res/values-es-rUS/values-es-rUS.xml diff --git a/library/dialpad/src/main/res/values-es/values-es.xml b/library/external/dialpad/src/main/res/values-es/values-es.xml similarity index 100% rename from library/dialpad/src/main/res/values-es/values-es.xml rename to library/external/dialpad/src/main/res/values-es/values-es.xml diff --git a/library/dialpad/src/main/res/values-et/values-et.xml b/library/external/dialpad/src/main/res/values-et/values-et.xml similarity index 100% rename from library/dialpad/src/main/res/values-et/values-et.xml rename to library/external/dialpad/src/main/res/values-et/values-et.xml diff --git a/library/dialpad/src/main/res/values-eu/values-eu.xml b/library/external/dialpad/src/main/res/values-eu/values-eu.xml similarity index 100% rename from library/dialpad/src/main/res/values-eu/values-eu.xml rename to library/external/dialpad/src/main/res/values-eu/values-eu.xml diff --git a/library/dialpad/src/main/res/values-fa/values-fa.xml b/library/external/dialpad/src/main/res/values-fa/values-fa.xml similarity index 100% rename from library/dialpad/src/main/res/values-fa/values-fa.xml rename to library/external/dialpad/src/main/res/values-fa/values-fa.xml diff --git a/library/dialpad/src/main/res/values-fi/values-fi.xml b/library/external/dialpad/src/main/res/values-fi/values-fi.xml similarity index 100% rename from library/dialpad/src/main/res/values-fi/values-fi.xml rename to library/external/dialpad/src/main/res/values-fi/values-fi.xml diff --git a/library/dialpad/src/main/res/values-fr-rCA/values-fr-rCA.xml b/library/external/dialpad/src/main/res/values-fr-rCA/values-fr-rCA.xml similarity index 100% rename from library/dialpad/src/main/res/values-fr-rCA/values-fr-rCA.xml rename to library/external/dialpad/src/main/res/values-fr-rCA/values-fr-rCA.xml diff --git a/library/dialpad/src/main/res/values-fr/values-fr.xml b/library/external/dialpad/src/main/res/values-fr/values-fr.xml similarity index 100% rename from library/dialpad/src/main/res/values-fr/values-fr.xml rename to library/external/dialpad/src/main/res/values-fr/values-fr.xml diff --git a/library/dialpad/src/main/res/values-gl/values-gl.xml b/library/external/dialpad/src/main/res/values-gl/values-gl.xml similarity index 100% rename from library/dialpad/src/main/res/values-gl/values-gl.xml rename to library/external/dialpad/src/main/res/values-gl/values-gl.xml diff --git a/library/dialpad/src/main/res/values-gu/values-gu.xml b/library/external/dialpad/src/main/res/values-gu/values-gu.xml similarity index 100% rename from library/dialpad/src/main/res/values-gu/values-gu.xml rename to library/external/dialpad/src/main/res/values-gu/values-gu.xml diff --git a/library/dialpad/src/main/res/values-hi/values-hi.xml b/library/external/dialpad/src/main/res/values-hi/values-hi.xml similarity index 100% rename from library/dialpad/src/main/res/values-hi/values-hi.xml rename to library/external/dialpad/src/main/res/values-hi/values-hi.xml diff --git a/library/dialpad/src/main/res/values-hr/values-hr.xml b/library/external/dialpad/src/main/res/values-hr/values-hr.xml similarity index 100% rename from library/dialpad/src/main/res/values-hr/values-hr.xml rename to library/external/dialpad/src/main/res/values-hr/values-hr.xml diff --git a/library/dialpad/src/main/res/values-hu/values-hu.xml b/library/external/dialpad/src/main/res/values-hu/values-hu.xml similarity index 100% rename from library/dialpad/src/main/res/values-hu/values-hu.xml rename to library/external/dialpad/src/main/res/values-hu/values-hu.xml diff --git a/library/dialpad/src/main/res/values-hy/values-hy.xml b/library/external/dialpad/src/main/res/values-hy/values-hy.xml similarity index 100% rename from library/dialpad/src/main/res/values-hy/values-hy.xml rename to library/external/dialpad/src/main/res/values-hy/values-hy.xml diff --git a/library/dialpad/src/main/res/values-in/values-in.xml b/library/external/dialpad/src/main/res/values-in/values-in.xml similarity index 100% rename from library/dialpad/src/main/res/values-in/values-in.xml rename to library/external/dialpad/src/main/res/values-in/values-in.xml diff --git a/library/dialpad/src/main/res/values-is/values-is.xml b/library/external/dialpad/src/main/res/values-is/values-is.xml similarity index 100% rename from library/dialpad/src/main/res/values-is/values-is.xml rename to library/external/dialpad/src/main/res/values-is/values-is.xml diff --git a/library/dialpad/src/main/res/values-it/values-it.xml b/library/external/dialpad/src/main/res/values-it/values-it.xml similarity index 100% rename from library/dialpad/src/main/res/values-it/values-it.xml rename to library/external/dialpad/src/main/res/values-it/values-it.xml diff --git a/library/dialpad/src/main/res/values-iw/values-iw.xml b/library/external/dialpad/src/main/res/values-iw/values-iw.xml similarity index 100% rename from library/dialpad/src/main/res/values-iw/values-iw.xml rename to library/external/dialpad/src/main/res/values-iw/values-iw.xml diff --git a/library/dialpad/src/main/res/values-ja/values-ja.xml b/library/external/dialpad/src/main/res/values-ja/values-ja.xml similarity index 100% rename from library/dialpad/src/main/res/values-ja/values-ja.xml rename to library/external/dialpad/src/main/res/values-ja/values-ja.xml diff --git a/library/dialpad/src/main/res/values-ka/values-ka.xml b/library/external/dialpad/src/main/res/values-ka/values-ka.xml similarity index 100% rename from library/dialpad/src/main/res/values-ka/values-ka.xml rename to library/external/dialpad/src/main/res/values-ka/values-ka.xml diff --git a/library/dialpad/src/main/res/values-kk/values-kk.xml b/library/external/dialpad/src/main/res/values-kk/values-kk.xml similarity index 100% rename from library/dialpad/src/main/res/values-kk/values-kk.xml rename to library/external/dialpad/src/main/res/values-kk/values-kk.xml diff --git a/library/dialpad/src/main/res/values-km/values-km.xml b/library/external/dialpad/src/main/res/values-km/values-km.xml similarity index 100% rename from library/dialpad/src/main/res/values-km/values-km.xml rename to library/external/dialpad/src/main/res/values-km/values-km.xml diff --git a/library/dialpad/src/main/res/values-kn/values-kn.xml b/library/external/dialpad/src/main/res/values-kn/values-kn.xml similarity index 100% rename from library/dialpad/src/main/res/values-kn/values-kn.xml rename to library/external/dialpad/src/main/res/values-kn/values-kn.xml diff --git a/library/dialpad/src/main/res/values-ko/values-ko.xml b/library/external/dialpad/src/main/res/values-ko/values-ko.xml similarity index 100% rename from library/dialpad/src/main/res/values-ko/values-ko.xml rename to library/external/dialpad/src/main/res/values-ko/values-ko.xml diff --git a/library/dialpad/src/main/res/values-ky/values-ky.xml b/library/external/dialpad/src/main/res/values-ky/values-ky.xml similarity index 100% rename from library/dialpad/src/main/res/values-ky/values-ky.xml rename to library/external/dialpad/src/main/res/values-ky/values-ky.xml diff --git a/library/dialpad/src/main/res/values-land/values-land.xml b/library/external/dialpad/src/main/res/values-land/values-land.xml similarity index 100% rename from library/dialpad/src/main/res/values-land/values-land.xml rename to library/external/dialpad/src/main/res/values-land/values-land.xml diff --git a/library/dialpad/src/main/res/values-lo/values-lo.xml b/library/external/dialpad/src/main/res/values-lo/values-lo.xml similarity index 100% rename from library/dialpad/src/main/res/values-lo/values-lo.xml rename to library/external/dialpad/src/main/res/values-lo/values-lo.xml diff --git a/library/dialpad/src/main/res/values-lt/values-lt.xml b/library/external/dialpad/src/main/res/values-lt/values-lt.xml similarity index 100% rename from library/dialpad/src/main/res/values-lt/values-lt.xml rename to library/external/dialpad/src/main/res/values-lt/values-lt.xml diff --git a/library/dialpad/src/main/res/values-lv/values-lv.xml b/library/external/dialpad/src/main/res/values-lv/values-lv.xml similarity index 100% rename from library/dialpad/src/main/res/values-lv/values-lv.xml rename to library/external/dialpad/src/main/res/values-lv/values-lv.xml diff --git a/library/dialpad/src/main/res/values-mk/values-mk.xml b/library/external/dialpad/src/main/res/values-mk/values-mk.xml similarity index 100% rename from library/dialpad/src/main/res/values-mk/values-mk.xml rename to library/external/dialpad/src/main/res/values-mk/values-mk.xml diff --git a/library/dialpad/src/main/res/values-ml/values-ml.xml b/library/external/dialpad/src/main/res/values-ml/values-ml.xml similarity index 100% rename from library/dialpad/src/main/res/values-ml/values-ml.xml rename to library/external/dialpad/src/main/res/values-ml/values-ml.xml diff --git a/library/dialpad/src/main/res/values-mn/values-mn.xml b/library/external/dialpad/src/main/res/values-mn/values-mn.xml similarity index 100% rename from library/dialpad/src/main/res/values-mn/values-mn.xml rename to library/external/dialpad/src/main/res/values-mn/values-mn.xml diff --git a/library/dialpad/src/main/res/values-mr/values-mr.xml b/library/external/dialpad/src/main/res/values-mr/values-mr.xml similarity index 100% rename from library/dialpad/src/main/res/values-mr/values-mr.xml rename to library/external/dialpad/src/main/res/values-mr/values-mr.xml diff --git a/library/dialpad/src/main/res/values-ms/values-ms.xml b/library/external/dialpad/src/main/res/values-ms/values-ms.xml similarity index 100% rename from library/dialpad/src/main/res/values-ms/values-ms.xml rename to library/external/dialpad/src/main/res/values-ms/values-ms.xml diff --git a/library/dialpad/src/main/res/values-my/values-my.xml b/library/external/dialpad/src/main/res/values-my/values-my.xml similarity index 100% rename from library/dialpad/src/main/res/values-my/values-my.xml rename to library/external/dialpad/src/main/res/values-my/values-my.xml diff --git a/library/dialpad/src/main/res/values-nb/values-nb.xml b/library/external/dialpad/src/main/res/values-nb/values-nb.xml similarity index 100% rename from library/dialpad/src/main/res/values-nb/values-nb.xml rename to library/external/dialpad/src/main/res/values-nb/values-nb.xml diff --git a/library/dialpad/src/main/res/values-ne/values-ne.xml b/library/external/dialpad/src/main/res/values-ne/values-ne.xml similarity index 100% rename from library/dialpad/src/main/res/values-ne/values-ne.xml rename to library/external/dialpad/src/main/res/values-ne/values-ne.xml diff --git a/library/dialpad/src/main/res/values-nl/values-nl.xml b/library/external/dialpad/src/main/res/values-nl/values-nl.xml similarity index 100% rename from library/dialpad/src/main/res/values-nl/values-nl.xml rename to library/external/dialpad/src/main/res/values-nl/values-nl.xml diff --git a/library/dialpad/src/main/res/values-no/values-no.xml b/library/external/dialpad/src/main/res/values-no/values-no.xml similarity index 100% rename from library/dialpad/src/main/res/values-no/values-no.xml rename to library/external/dialpad/src/main/res/values-no/values-no.xml diff --git a/library/dialpad/src/main/res/values-pa/values-pa.xml b/library/external/dialpad/src/main/res/values-pa/values-pa.xml similarity index 100% rename from library/dialpad/src/main/res/values-pa/values-pa.xml rename to library/external/dialpad/src/main/res/values-pa/values-pa.xml diff --git a/library/dialpad/src/main/res/values-pl/values-pl.xml b/library/external/dialpad/src/main/res/values-pl/values-pl.xml similarity index 100% rename from library/dialpad/src/main/res/values-pl/values-pl.xml rename to library/external/dialpad/src/main/res/values-pl/values-pl.xml diff --git a/library/dialpad/src/main/res/values-pt-rBR/values-pt-rBR.xml b/library/external/dialpad/src/main/res/values-pt-rBR/values-pt-rBR.xml similarity index 100% rename from library/dialpad/src/main/res/values-pt-rBR/values-pt-rBR.xml rename to library/external/dialpad/src/main/res/values-pt-rBR/values-pt-rBR.xml diff --git a/library/dialpad/src/main/res/values-pt-rPT/values-pt-rPT.xml b/library/external/dialpad/src/main/res/values-pt-rPT/values-pt-rPT.xml similarity index 100% rename from library/dialpad/src/main/res/values-pt-rPT/values-pt-rPT.xml rename to library/external/dialpad/src/main/res/values-pt-rPT/values-pt-rPT.xml diff --git a/library/dialpad/src/main/res/values-pt/values-pt.xml b/library/external/dialpad/src/main/res/values-pt/values-pt.xml similarity index 100% rename from library/dialpad/src/main/res/values-pt/values-pt.xml rename to library/external/dialpad/src/main/res/values-pt/values-pt.xml diff --git a/library/dialpad/src/main/res/values-ro/values-ro.xml b/library/external/dialpad/src/main/res/values-ro/values-ro.xml similarity index 100% rename from library/dialpad/src/main/res/values-ro/values-ro.xml rename to library/external/dialpad/src/main/res/values-ro/values-ro.xml diff --git a/library/dialpad/src/main/res/values-ru/values-ru.xml b/library/external/dialpad/src/main/res/values-ru/values-ru.xml similarity index 100% rename from library/dialpad/src/main/res/values-ru/values-ru.xml rename to library/external/dialpad/src/main/res/values-ru/values-ru.xml diff --git a/library/dialpad/src/main/res/values-si/values-si.xml b/library/external/dialpad/src/main/res/values-si/values-si.xml similarity index 100% rename from library/dialpad/src/main/res/values-si/values-si.xml rename to library/external/dialpad/src/main/res/values-si/values-si.xml diff --git a/library/dialpad/src/main/res/values-sk/values-sk.xml b/library/external/dialpad/src/main/res/values-sk/values-sk.xml similarity index 100% rename from library/dialpad/src/main/res/values-sk/values-sk.xml rename to library/external/dialpad/src/main/res/values-sk/values-sk.xml diff --git a/library/dialpad/src/main/res/values-sl/values-sl.xml b/library/external/dialpad/src/main/res/values-sl/values-sl.xml similarity index 100% rename from library/dialpad/src/main/res/values-sl/values-sl.xml rename to library/external/dialpad/src/main/res/values-sl/values-sl.xml diff --git a/library/dialpad/src/main/res/values-sq/values-sq.xml b/library/external/dialpad/src/main/res/values-sq/values-sq.xml similarity index 100% rename from library/dialpad/src/main/res/values-sq/values-sq.xml rename to library/external/dialpad/src/main/res/values-sq/values-sq.xml diff --git a/library/dialpad/src/main/res/values-sr/values-sr.xml b/library/external/dialpad/src/main/res/values-sr/values-sr.xml similarity index 100% rename from library/dialpad/src/main/res/values-sr/values-sr.xml rename to library/external/dialpad/src/main/res/values-sr/values-sr.xml diff --git a/library/dialpad/src/main/res/values-sv/values-sv.xml b/library/external/dialpad/src/main/res/values-sv/values-sv.xml similarity index 100% rename from library/dialpad/src/main/res/values-sv/values-sv.xml rename to library/external/dialpad/src/main/res/values-sv/values-sv.xml diff --git a/library/dialpad/src/main/res/values-sw/values-sw.xml b/library/external/dialpad/src/main/res/values-sw/values-sw.xml similarity index 100% rename from library/dialpad/src/main/res/values-sw/values-sw.xml rename to library/external/dialpad/src/main/res/values-sw/values-sw.xml diff --git a/library/dialpad/src/main/res/values-ta/values-ta.xml b/library/external/dialpad/src/main/res/values-ta/values-ta.xml similarity index 100% rename from library/dialpad/src/main/res/values-ta/values-ta.xml rename to library/external/dialpad/src/main/res/values-ta/values-ta.xml diff --git a/library/dialpad/src/main/res/values-te/values-te.xml b/library/external/dialpad/src/main/res/values-te/values-te.xml similarity index 100% rename from library/dialpad/src/main/res/values-te/values-te.xml rename to library/external/dialpad/src/main/res/values-te/values-te.xml diff --git a/library/dialpad/src/main/res/values-th/values-th.xml b/library/external/dialpad/src/main/res/values-th/values-th.xml similarity index 100% rename from library/dialpad/src/main/res/values-th/values-th.xml rename to library/external/dialpad/src/main/res/values-th/values-th.xml diff --git a/library/dialpad/src/main/res/values-tl/values-tl.xml b/library/external/dialpad/src/main/res/values-tl/values-tl.xml similarity index 100% rename from library/dialpad/src/main/res/values-tl/values-tl.xml rename to library/external/dialpad/src/main/res/values-tl/values-tl.xml diff --git a/library/dialpad/src/main/res/values-tr/values-tr.xml b/library/external/dialpad/src/main/res/values-tr/values-tr.xml similarity index 100% rename from library/dialpad/src/main/res/values-tr/values-tr.xml rename to library/external/dialpad/src/main/res/values-tr/values-tr.xml diff --git a/library/dialpad/src/main/res/values-uk/values-uk.xml b/library/external/dialpad/src/main/res/values-uk/values-uk.xml similarity index 100% rename from library/dialpad/src/main/res/values-uk/values-uk.xml rename to library/external/dialpad/src/main/res/values-uk/values-uk.xml diff --git a/library/dialpad/src/main/res/values-ur/values-ur.xml b/library/external/dialpad/src/main/res/values-ur/values-ur.xml similarity index 100% rename from library/dialpad/src/main/res/values-ur/values-ur.xml rename to library/external/dialpad/src/main/res/values-ur/values-ur.xml diff --git a/library/dialpad/src/main/res/values-uz/values-uz.xml b/library/external/dialpad/src/main/res/values-uz/values-uz.xml similarity index 100% rename from library/dialpad/src/main/res/values-uz/values-uz.xml rename to library/external/dialpad/src/main/res/values-uz/values-uz.xml diff --git a/library/dialpad/src/main/res/values-vi/values-vi.xml b/library/external/dialpad/src/main/res/values-vi/values-vi.xml similarity index 100% rename from library/dialpad/src/main/res/values-vi/values-vi.xml rename to library/external/dialpad/src/main/res/values-vi/values-vi.xml diff --git a/library/dialpad/src/main/res/values-zh-rCN/values-zh-rCN.xml b/library/external/dialpad/src/main/res/values-zh-rCN/values-zh-rCN.xml similarity index 100% rename from library/dialpad/src/main/res/values-zh-rCN/values-zh-rCN.xml rename to library/external/dialpad/src/main/res/values-zh-rCN/values-zh-rCN.xml diff --git a/library/dialpad/src/main/res/values-zh-rHK/values-zh-rHK.xml b/library/external/dialpad/src/main/res/values-zh-rHK/values-zh-rHK.xml similarity index 100% rename from library/dialpad/src/main/res/values-zh-rHK/values-zh-rHK.xml rename to library/external/dialpad/src/main/res/values-zh-rHK/values-zh-rHK.xml diff --git a/library/dialpad/src/main/res/values-zh-rTW/values-zh-rTW.xml b/library/external/dialpad/src/main/res/values-zh-rTW/values-zh-rTW.xml similarity index 100% rename from library/dialpad/src/main/res/values-zh-rTW/values-zh-rTW.xml rename to library/external/dialpad/src/main/res/values-zh-rTW/values-zh-rTW.xml diff --git a/library/dialpad/src/main/res/values-zu/values-zu.xml b/library/external/dialpad/src/main/res/values-zu/values-zu.xml similarity index 100% rename from library/dialpad/src/main/res/values-zu/values-zu.xml rename to library/external/dialpad/src/main/res/values-zu/values-zu.xml diff --git a/library/dialpad/src/main/res/values/values.xml b/library/external/dialpad/src/main/res/values/values.xml similarity index 100% rename from library/dialpad/src/main/res/values/values.xml rename to library/external/dialpad/src/main/res/values/values.xml diff --git a/library/diff-match-patch/.gitignore b/library/external/diff-match-patch/.gitignore similarity index 100% rename from library/diff-match-patch/.gitignore rename to library/external/diff-match-patch/.gitignore diff --git a/library/diff-match-patch/build.gradle b/library/external/diff-match-patch/build.gradle similarity index 100% rename from library/diff-match-patch/build.gradle rename to library/external/diff-match-patch/build.gradle diff --git a/library/diff-match-patch/src/main/java/name/fraser/neil/plaintext/diff_match_patch.java b/library/external/diff-match-patch/src/main/java/name/fraser/neil/plaintext/diff_match_patch.java similarity index 100% rename from library/diff-match-patch/src/main/java/name/fraser/neil/plaintext/diff_match_patch.java rename to library/external/diff-match-patch/src/main/java/name/fraser/neil/plaintext/diff_match_patch.java diff --git a/library/jsonviewer/.gitignore b/library/external/jsonviewer/.gitignore similarity index 100% rename from library/jsonviewer/.gitignore rename to library/external/jsonviewer/.gitignore diff --git a/library/jsonviewer/build.gradle b/library/external/jsonviewer/build.gradle similarity index 100% rename from library/jsonviewer/build.gradle rename to library/external/jsonviewer/build.gradle diff --git a/library/jsonviewer/src/main/AndroidManifest.xml b/library/external/jsonviewer/src/main/AndroidManifest.xml similarity index 100% rename from library/jsonviewer/src/main/AndroidManifest.xml rename to library/external/jsonviewer/src/main/AndroidManifest.xml diff --git a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerDialog.kt b/library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerDialog.kt similarity index 100% rename from library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerDialog.kt rename to library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerDialog.kt diff --git a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerEpoxyController.kt b/library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerEpoxyController.kt similarity index 100% rename from library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerEpoxyController.kt rename to library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerEpoxyController.kt diff --git a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerFragment.kt b/library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerFragment.kt similarity index 100% rename from library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerFragment.kt rename to library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerFragment.kt diff --git a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerModel.kt b/library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerModel.kt similarity index 100% rename from library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerModel.kt rename to library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerModel.kt diff --git a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerStyleProvider.kt b/library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerStyleProvider.kt similarity index 100% rename from library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerStyleProvider.kt rename to library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerStyleProvider.kt diff --git a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerViewModel.kt b/library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerViewModel.kt similarity index 100% rename from library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerViewModel.kt rename to library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/JSonViewerViewModel.kt diff --git a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/Utils.kt b/library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/Utils.kt similarity index 100% rename from library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/Utils.kt rename to library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/Utils.kt diff --git a/library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/ValueItem.kt b/library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/ValueItem.kt similarity index 100% rename from library/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/ValueItem.kt rename to library/external/jsonviewer/src/main/java/org/billcarsonfr/jsonviewer/ValueItem.kt diff --git a/library/jsonviewer/src/main/res/layout/fragment_dialog_jv.xml b/library/external/jsonviewer/src/main/res/layout/fragment_dialog_jv.xml similarity index 100% rename from library/jsonviewer/src/main/res/layout/fragment_dialog_jv.xml rename to library/external/jsonviewer/src/main/res/layout/fragment_dialog_jv.xml diff --git a/library/jsonviewer/src/main/res/layout/fragment_jv_recycler_view.xml b/library/external/jsonviewer/src/main/res/layout/fragment_jv_recycler_view.xml similarity index 100% rename from library/jsonviewer/src/main/res/layout/fragment_jv_recycler_view.xml rename to library/external/jsonviewer/src/main/res/layout/fragment_jv_recycler_view.xml diff --git a/library/jsonviewer/src/main/res/layout/fragment_jv_recycler_view_wrap.xml b/library/external/jsonviewer/src/main/res/layout/fragment_jv_recycler_view_wrap.xml similarity index 100% rename from library/jsonviewer/src/main/res/layout/fragment_jv_recycler_view_wrap.xml rename to library/external/jsonviewer/src/main/res/layout/fragment_jv_recycler_view_wrap.xml diff --git a/library/jsonviewer/src/main/res/layout/item_jv_base_value.xml b/library/external/jsonviewer/src/main/res/layout/item_jv_base_value.xml similarity index 100% rename from library/jsonviewer/src/main/res/layout/item_jv_base_value.xml rename to library/external/jsonviewer/src/main/res/layout/item_jv_base_value.xml diff --git a/library/jsonviewer/src/main/res/values/colors.xml b/library/external/jsonviewer/src/main/res/values/colors.xml similarity index 100% rename from library/jsonviewer/src/main/res/values/colors.xml rename to library/external/jsonviewer/src/main/res/values/colors.xml diff --git a/library/jsonviewer/src/main/res/values/strings.xml b/library/external/jsonviewer/src/main/res/values/strings.xml similarity index 100% rename from library/jsonviewer/src/main/res/values/strings.xml rename to library/external/jsonviewer/src/main/res/values/strings.xml diff --git a/library/jsonviewer/src/test/java/org/billcarsonfr/jsonviewer/ModelParseTest.kt b/library/external/jsonviewer/src/test/java/org/billcarsonfr/jsonviewer/ModelParseTest.kt similarity index 100% rename from library/jsonviewer/src/test/java/org/billcarsonfr/jsonviewer/ModelParseTest.kt rename to library/external/jsonviewer/src/test/java/org/billcarsonfr/jsonviewer/ModelParseTest.kt diff --git a/library/ui-styles/build.gradle b/library/ui-styles/build.gradle index 804eb3aae9..ee5771d995 100644 --- a/library/ui-styles/build.gradle +++ b/library/ui-styles/build.gradle @@ -58,5 +58,5 @@ dependencies { // Pref theme implementation libs.androidx.preferenceKtx // dialpad dimen - implementation project(":library:dialpad") + implementation project(":library:external:dialpad") } diff --git a/settings.gradle b/settings.gradle index e43d1f6d75..d35476f769 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,13 +1,16 @@ include ':vector-app' include ':vector' include ':vector-config' -include ':matrix-sdk-android' + include ':library:core-utils' include ':library:ui-strings' include ':library:ui-styles' -include ':library:jsonviewer' include ':library:attachment-viewer' -include ':library:diff-match-patch' include ':library:multipicker' -include ':library:dialpad' + +include ':library:external:jsonviewer' +include ':library:external:diff-match-patch' +include ':library:external:dialpad' + +include ':matrix-sdk-android' include ':matrix-sdk-android-flow' diff --git a/vector/build.gradle b/vector/build.gradle index 67e3f92ee5..0335575bf3 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -104,12 +104,12 @@ dependencies { implementation project(":vector-config") api project(":matrix-sdk-android") implementation project(":matrix-sdk-android-flow") - implementation project(":library:jsonviewer") + implementation project(":library:external:jsonviewer") + implementation project(":library:external:diff-match-patch") implementation project(":library:ui-strings") implementation project(":library:ui-styles") implementation project(":library:core-utils") implementation project(":library:attachment-viewer") - implementation project(":library:diff-match-patch") implementation project(":library:multipicker") implementation libs.jetbrains.coroutinesCore @@ -265,7 +265,7 @@ dependencies { api libs.vanniktech.emojiMaterial api libs.vanniktech.emojiGoogle - implementation project(":library:dialpad") + implementation project(":library:external:dialpad") // JWT api libs.jsonwebtoken.jjwtApi From 4a0cda32687157b599761ccb717187950af07ca7 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Fri, 16 Sep 2022 16:31:45 +0100 Subject: [PATCH 017/187] formatting tweaks --- docs/unit_testing.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/unit_testing.md b/docs/unit_testing.md index d879ba18e7..5643e9709c 100644 --- a/docs/unit_testing.md +++ b/docs/unit_testing.md @@ -2,8 +2,8 @@ -* [Overview](#project-conventions) - * [Best Practices](#best-practices) +* [Overview](#overview) + * [Best Practices](#best-practices) * [Project Conventions](#project-conventions) * [Setup](#setup) * [Naming](#naming) @@ -13,10 +13,9 @@ * [Mocking](#mocking) * [Fakes](#fakes) * [Fixtures](#fixtures) -* [Examples](#examples) - * [Simple](#extensions-used-to-streamline-the-test-setup) - * [Fakes and Fixtures](#fakes-and-fixtures) - * [ViewModel](#viewmodel) + * [Examples](#examples) + * [Extensions used to streamline the test setup](#extensions-used-to-streamline-the-test-setup) + * [Fakes and Fixtures](#fakes-and-fixtures) @@ -65,11 +64,11 @@ class MyClassTest { #### Naming -- Test names use the `Gherkin` format, `given, when, then`mapping to the input, logic under test and expected result. +- Test names use the `Gherkin` format, `given, when, then` mapping to the input, logic under test and expected result. - `given` - Uniqueness about the environment or dependencies in which the test case is running. _"given device is android 12 and supports dark mode"_ - `when` - The action/function under test. _"when reading dark mode status"_ - `then` - The expected result from the combination of _given_ and _when_. _"then returns dark mode enabled"_ -- Test names are written using kotlin back ticks to enable _sentences _ish_. +- Test names are written using kotlin back ticks to enable sentences _ish_. ```kotlin @Test From 0385f387d9096de6a82c16f3eeb27731c1ab228d Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Fri, 16 Sep 2022 16:33:17 +0100 Subject: [PATCH 018/187] using value notion instead of key for the elements in the circular cache --- docs/unit_testing.md | 4 ++-- .../im/vector/app/features/notifications/CircularCache.kt | 6 +++--- .../vector/app/features/notifications/CircularCacheTest.kt | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/unit_testing.md b/docs/unit_testing.md index 5643e9709c..f786c9a160 100644 --- a/docs/unit_testing.md +++ b/docs/unit_testing.md @@ -259,8 +259,8 @@ private fun createIntCache(cacheSize: Int): Pair, Array return CircularCache(cacheSize, factory) to internalData!! } -private fun CircularCache.putInOrder(vararg keys: Int) { - keys.forEach { put(it) } +private fun CircularCache.putInOrder(vararg values: Int) { + values.forEach { put(it) } } ``` diff --git a/vector/src/main/java/im/vector/app/features/notifications/CircularCache.kt b/vector/src/main/java/im/vector/app/features/notifications/CircularCache.kt index 5c751e0d55..6c9b8b2e6c 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/CircularCache.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/CircularCache.kt @@ -29,13 +29,13 @@ class CircularCache(cacheSize: Int, factory: (Int) -> Array) { private val cache = factory(cacheSize) private var writeIndex = 0 - fun contains(key: T): Boolean = cache.contains(key) + fun contains(value: T): Boolean = cache.contains(value) - fun put(key: T) { + fun put(value: T) { if (writeIndex == cache.size) { writeIndex = 0 } - cache[writeIndex] = key + cache[writeIndex] = value writeIndex++ } } diff --git a/vector/src/test/java/im/vector/app/features/notifications/CircularCacheTest.kt b/vector/src/test/java/im/vector/app/features/notifications/CircularCacheTest.kt index 6428b1025b..509e2a8e29 100644 --- a/vector/src/test/java/im/vector/app/features/notifications/CircularCacheTest.kt +++ b/vector/src/test/java/im/vector/app/features/notifications/CircularCacheTest.kt @@ -66,7 +66,7 @@ class CircularCacheTest { return CircularCache(cacheSize, factory) to internalData!! } - private fun CircularCache.putInOrder(vararg keys: Int) { - keys.forEach { put(it) } + private fun CircularCache.putInOrder(vararg values: Int) { + values.forEach { put(it) } } } From ea274c4df60dadf4dadb7f4e748e1df59f01806c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 Aug 2022 23:11:34 +0000 Subject: [PATCH 019/187] Bump appcompat from 1.4.2 to 1.5.0 Bumps appcompat from 1.4.2 to 1.5.0. --- updated-dependencies: - dependency-name: androidx.appcompat:appcompat dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 9641a63f26..6b827e834e 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -51,7 +51,7 @@ ext.libs = [ ], androidx : [ 'activity' : "androidx.activity:activity:1.5.1", - 'appCompat' : "androidx.appcompat:appcompat:1.4.2", + 'appCompat' : "androidx.appcompat:appcompat:1.5.0", 'biometric' : "androidx.biometric:biometric:1.1.0", 'core' : "androidx.core:core-ktx:1.8.0", 'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1", From d9ee51a2122aaed30b1a2b85fc7befdd495909ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 17 Aug 2022 13:16:52 +0000 Subject: [PATCH 020/187] Bump emoji2 from 1.1.0 to 1.2.0 Bumps emoji2 from 1.1.0 to 1.2.0. --- updated-dependencies: - dependency-name: androidx.emoji2:emoji2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- vector/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/build.gradle b/vector/build.gradle index ac3699454c..740f2710c0 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -232,7 +232,7 @@ dependencies { // UnifiedPush implementation 'com.github.UnifiedPush:android-connector:2.0.1' - implementation "androidx.emoji2:emoji2:1.1.0" + implementation "androidx.emoji2:emoji2:1.2.0" // WebRTC // org.webrtc:google-webrtc is for development purposes only From 8b64bd38b72b72beb49b7849058fde796e1f9a0c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 24 Aug 2022 16:32:05 +0200 Subject: [PATCH 021/187] 'compileSdk': 32, 'targetSdk': 32 --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 6b827e834e..8a93950c15 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,8 +1,8 @@ ext.versions = [ 'minSdk' : 21, - 'compileSdk' : 31, - 'targetSdk' : 31, + 'compileSdk' : 32, + 'targetSdk' : 32, 'sourceCompat' : JavaVersion.VERSION_11, 'targetCompat' : JavaVersion.VERSION_11, ] From 3f3c83a43d8f380f93c3f315e9381633414b1a20 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 24 Aug 2022 17:03:38 +0200 Subject: [PATCH 022/187] Remove deprecated internal class. --- .../send/queue/EventSenderProcessorThread.kt | 235 ------------------ 1 file changed, 235 deletions(-) delete mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt deleted file mode 100644 index 55363a7251..0000000000 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/send/queue/EventSenderProcessorThread.kt +++ /dev/null @@ -1,235 +0,0 @@ -/* - * Copyright 2020 The Matrix.org Foundation C.I.C. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.matrix.android.sdk.internal.session.room.send.queue - -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking -import org.matrix.android.sdk.api.auth.data.SessionParams -import org.matrix.android.sdk.api.auth.data.sessionId -import org.matrix.android.sdk.api.extensions.tryOrNull -import org.matrix.android.sdk.api.failure.Failure -import org.matrix.android.sdk.api.failure.isLimitExceededError -import org.matrix.android.sdk.api.failure.isTokenError -import org.matrix.android.sdk.api.session.Session -import org.matrix.android.sdk.api.session.crypto.CryptoService -import org.matrix.android.sdk.api.session.events.model.Event -import org.matrix.android.sdk.api.session.sync.SyncState -import org.matrix.android.sdk.api.util.Cancelable -import org.matrix.android.sdk.internal.session.SessionScope -import org.matrix.android.sdk.internal.task.TaskExecutor -import timber.log.Timber -import java.io.IOException -import java.util.Timer -import java.util.TimerTask -import java.util.concurrent.LinkedBlockingQueue -import javax.inject.Inject -import kotlin.concurrent.schedule - -/** - * A simple ever running thread unique for that session responsible of sending events in order. - * Each send is retried 3 times, if there is no network (e.g if cannot ping homeserver) it will wait and - * periodically test reachability before resume (does not count as a retry) - * - * If the app is killed before all event were sent, on next wakeup the scheduled events will be re posted - */ -@Deprecated("You should know use EventSenderProcessorCoroutine instead") -@SessionScope -internal class EventSenderProcessorThread @Inject constructor( - private val cryptoService: CryptoService, - private val sessionParams: SessionParams, - private val queuedTaskFactory: QueuedTaskFactory, - private val taskExecutor: TaskExecutor, - private val memento: QueueMemento -) : Thread("Matrix-SENDER_THREAD_SID_${sessionParams.credentials.sessionId()}"), EventSenderProcessor { - - private fun markAsManaged(task: QueuedTask) { - memento.track(task) - } - - private fun markAsFinished(task: QueuedTask) { - memento.unTrack(task) - } - - override fun onSessionStarted(session: Session) { - start() - } - - override fun onSessionStopped(session: Session) { - interrupt() - } - - override fun start() { - super.start() - // We should check for sending events not handled because app was killed - // But we should be careful of only took those that was submitted to us, because if it's - // for example it's a media event it is handled by some worker and he will handle it - // This is a bit fragile :/ - // also some events cannot be retried manually by users, e.g reactions - // they were previously relying on workers to do the work :/ and was expected to always finally succeed - // Also some echos are not to be resent like redaction echos (fake event created for aggregation) - - tryOrNull { - taskExecutor.executorScope.launch { - Timber.d("## Send relaunched pending events on restart") - memento.restoreTasks(this@EventSenderProcessorThread) - } - } - } - - // API - override fun postEvent(event: Event): Cancelable { - return postEvent(event, event.roomId?.let { cryptoService.isRoomEncrypted(it) } ?: false) - } - - override fun postEvent(event: Event, encrypt: Boolean): Cancelable { - val task = queuedTaskFactory.createSendTask(event, encrypt) - return postTask(task) - } - - override fun postRedaction(redactionLocalEcho: Event, reason: String?): Cancelable { - return postRedaction(redactionLocalEcho.eventId!!, redactionLocalEcho.redacts!!, redactionLocalEcho.roomId!!, reason) - } - - override fun postRedaction(redactionLocalEchoId: String, eventToRedactId: String, roomId: String, reason: String?): Cancelable { - val task = queuedTaskFactory.createRedactTask(redactionLocalEchoId, eventToRedactId, roomId, reason) - return postTask(task) - } - - override fun postTask(task: QueuedTask): Cancelable { - // non blocking add to queue - sendingQueue.add(task) - markAsManaged(task) - return task - } - - override fun cancel(eventId: String, roomId: String) { - (currentTask as? SendEventQueuedTask) - ?.takeIf { it.event.eventId == eventId && it.event.roomId == roomId } - ?.cancel() - } - - companion object { - private const val RETRY_WAIT_TIME_MS = 10_000L - } - - private var currentTask: QueuedTask? = null - - private var sendingQueue = LinkedBlockingQueue() - - private var networkAvailableLock = Object() - private var canReachServer = true - private var retryNoNetworkTask: TimerTask? = null - - override fun run() { - Timber.v("## SendThread started") - try { - while (!isInterrupted) { - Timber.v("## SendThread wait for task to process") - val task = sendingQueue.take() - .also { currentTask = it } - Timber.v("## SendThread Found task to process $task") - - if (task.isCancelled()) { - Timber.v("## SendThread send cancelled for $task") - // we do not execute this one - continue - } - // we check for network connectivity - while (!canReachServer) { - Timber.v("## SendThread cannot reach server") - // schedule to retry - waitForNetwork() - // if thread as been killed meanwhile -// if (state == State.KILLING) break - } - Timber.v("## Server is Reachable") - // so network is available - - runBlocking { - retryLoop@ while (task.retryCount.get() < 3) { - try { - // SendPerformanceProfiler.startStage(task.event.eventId!!, SendPerformanceProfiler.Stages.SEND_WORKER) - Timber.v("## SendThread retryLoop for $task retryCount ${task.retryCount}") - task.execute() - // sendEventTask.execute(SendEventTask.Params(task.event, task.encrypt, cryptoService)) - // SendPerformanceProfiler.stopStage(task.event.eventId, SendPerformanceProfiler.Stages.SEND_WORKER) - break@retryLoop - } catch (exception: Throwable) { - when { - exception is IOException || exception is Failure.NetworkConnection -> { - canReachServer = false - if (task.retryCount.getAndIncrement() >= 3) task.onTaskFailed() - while (!canReachServer) { - Timber.v("## SendThread retryLoop cannot reach server") - // schedule to retry - waitForNetwork() - } - } - (exception.isLimitExceededError()) -> { - if (task.retryCount.getAndIncrement() >= 3) task.onTaskFailed() - Timber.v("## SendThread retryLoop retryable error for $task reason: ${exception.localizedMessage}") - // wait a bit - // Todo if its a quota exception can we get timout? - sleep(3_000) - continue@retryLoop - } - exception.isTokenError() -> { - Timber.v("## SendThread retryLoop retryable TOKEN error, interrupt") - // we can exit the loop - task.onTaskFailed() - throw InterruptedException() - } - exception is CancellationException -> { - Timber.v("## SendThread task has been cancelled") - break@retryLoop - } - else -> { - Timber.v("## SendThread retryLoop Un-Retryable error, try next task") - // this task is in error, check next one? - task.onTaskFailed() - break@retryLoop - } - } - } - } - } - markAsFinished(task) - } - } catch (interruptionException: InterruptedException) { - // will be thrown is thread is interrupted while seeping - interrupt() - Timber.v("## InterruptedException!! ${interruptionException.localizedMessage}") - } -// state = State.KILLED - // is this needed? - retryNoNetworkTask?.cancel() - Timber.w("## SendThread finished") - } - - private fun waitForNetwork() { - retryNoNetworkTask = Timer(SyncState.NoNetwork.toString(), false).schedule(RETRY_WAIT_TIME_MS) { - synchronized(networkAvailableLock) { - canReachServer = HomeServerAvailabilityChecker(sessionParams).check().also { - Timber.v("## SendThread checkHostAvailable $it") - } - networkAvailableLock.notify() - } - } - synchronized(networkAvailableLock) { networkAvailableLock.wait() } - } -} From 24e4f94e61a3da054f842450f32f57a17aea0359 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 24 Aug 2022 17:30:36 +0200 Subject: [PATCH 023/187] Stop using deprecated method. --- .../uploads/media/RoomUploadsMediaFragment.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/media/RoomUploadsMediaFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/media/RoomUploadsMediaFragment.kt index f53f572e38..98a28557ae 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/media/RoomUploadsMediaFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/media/RoomUploadsMediaFragment.kt @@ -82,15 +82,18 @@ class RoomUploadsMediaFragment : controller.listener = this } - @Suppress("DEPRECATION") private fun getNumberOfColumns(): Int { - val displayMetrics = DisplayMetrics() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - requireContext().display?.getMetrics(displayMetrics) + val screenWidthInPx = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + val a = requireActivity().windowManager.currentWindowMetrics + a.bounds.width() } else { + val displayMetrics = DisplayMetrics() + @Suppress("DEPRECATION") requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics) + displayMetrics.widthPixels } - return dimensionConverter.pxToDp(displayMetrics.widthPixels) / IMAGE_SIZE_DP + val screenWidthInDp = dimensionConverter.pxToDp(screenWidthInPx) + return screenWidthInDp / IMAGE_SIZE_DP } override fun onDestroyView() { From 536b9cf926bb9ca285a49a81a93fb91b1c78e322 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 24 Aug 2022 17:38:00 +0200 Subject: [PATCH 024/187] Move `@Suppress("DEPRECATION")` closer to the deprecated usage. Will help to detect other deprecated API usage. --- .../lib/attachmentviewer/AttachmentViewerActivity.kt | 8 +++++--- .../sdk/internal/legacy/DefaultLegacySessionImporter.kt | 1 - .../im/vector/app/espresso/tools/ScreenshotFailureRule.kt | 1 - .../main/java/im/vector/app/core/extensions/Context.kt | 2 +- .../im/vector/app/core/platform/VectorBaseActivity.kt | 2 +- .../im/vector/app/core/utils/ExternalApplicationsUtil.kt | 3 +-- .../attachments/preview/AttachmentsPreviewFragment.kt | 2 +- .../lifecycle/VectorActivityLifecycleCallbacks.kt | 2 +- .../ui/fallbackprompt/FallbackBiometricDialogFragment.kt | 2 +- 9 files changed, 11 insertions(+), 12 deletions(-) diff --git a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt index 764cf8419a..0e8590f386 100644 --- a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt +++ b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt @@ -136,7 +136,6 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi } } - @Suppress("DEPRECATION") private fun setDecorViewFullScreen() { // This is important for the dispatchTouchEvent, if not we must correct // the touch coordinates @@ -155,11 +154,14 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi // new API instead of FLAG_TRANSLUCENT_NAVIGATION window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) } else { + @Suppress("DEPRECATION") window.decorView.systemUiVisibility = ( View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE) + @Suppress("DEPRECATION") window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) + @Suppress("DEPRECATION") window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION) } } @@ -344,7 +346,6 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi ?.handleCommand(commands) } - @Suppress("DEPRECATION") private fun hideSystemUI() { systemUiVisibility = false // Enables regular immersive mode. @@ -367,6 +368,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi // New API instead of FLAG_TRANSLUCENT_NAVIGATION window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) } else { + @Suppress("DEPRECATION") window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE // Set the content to appear under the system bars so that the // content doesn't resize when the system bars hide and show. @@ -381,13 +383,13 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi // Shows the system bars by removing all the flags // except for the ones that make the content appear under the system bars. - @Suppress("DEPRECATION") private fun showSystemUI() { systemUiVisibility = true if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION window.setDecorFitsSystemWindows(false) } else { + @Suppress("DEPRECATION") window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt index 7d52d9b2bf..567f605643 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt @@ -104,7 +104,6 @@ internal class DefaultLegacySessionImporter @Inject constructor( } private suspend fun importCredentials(legacyConfig: LegacyHomeServerConnectionConfig) { - @Suppress("DEPRECATION") val sessionParams = SessionParams( credentials = Credentials( userId = legacyConfig.credentials.userId, diff --git a/vector-app/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt b/vector-app/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt index 068c9fb646..5e131479bf 100644 --- a/vector-app/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt +++ b/vector-app/src/androidTest/java/im/vector/app/espresso/tools/ScreenshotFailureRule.kt @@ -92,7 +92,6 @@ private fun useMediaStoreScreenshotStorage( } } -@Suppress("DEPRECATION") private fun usePublicExternalScreenshotStorage( contentValues: ContentValues, contentResolver: ContentResolver, diff --git a/vector/src/main/java/im/vector/app/core/extensions/Context.kt b/vector/src/main/java/im/vector/app/core/extensions/Context.kt index 14e639bf32..1ed5aa8ba1 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Context.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Context.kt @@ -91,7 +91,6 @@ fun Context.safeOpenOutputStream(uri: Uri): OutputStream? { * * @return true if no active connection is found */ -@Suppress("deprecation") @SuppressLint("NewApi") // false positive fun Context.inferNoConnectivity(sdkIntProvider: BuildVersionSdkIntProvider): Boolean { val connectivityManager = getSystemService()!! @@ -104,6 +103,7 @@ fun Context.inferNoConnectivity(sdkIntProvider: BuildVersionSdkIntProvider): Boo else -> true } } else { + @Suppress("DEPRECATION") when (connectivityManager.activeNetworkInfo?.type) { ConnectivityManager.TYPE_WIFI -> false ConnectivityManager.TYPE_MOBILE -> false diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index c2c66ae69e..cb8c0ec8d1 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -464,7 +464,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver /** * Force to render the activity in fullscreen. */ - @Suppress("DEPRECATION") private fun setFullScreen() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION @@ -481,6 +480,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver // New API instead of FLAG_TRANSLUCENT_NAVIGATION window.navigationBarColor = ContextCompat.getColor(this, im.vector.lib.attachmentviewer.R.color.half_transparent_status_bar) } else { + @Suppress("DEPRECATION") window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN diff --git a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt index d52b7088ff..915a8d4d0d 100644 --- a/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt +++ b/vector/src/main/java/im/vector/app/core/utils/ExternalApplicationsUtil.kt @@ -309,7 +309,6 @@ suspend fun saveMedia( } } -@Suppress("DEPRECATION") private fun saveMediaLegacy( context: Context, mediaMimeType: String?, @@ -340,6 +339,7 @@ private fun saveMediaLegacy( val savedFile = saveFileIntoLegacy(file, downloadDir, outputFilename, currentTimeMillis) if (savedFile != null) { val downloadManager = context.getSystemService() + @Suppress("DEPRECATION") downloadManager?.addCompletedDownload( savedFile.name, title, @@ -430,7 +430,6 @@ fun selectTxtFileToWrite( * @param currentTimeMillis the current time in milliseconds * @return the created file */ -@Suppress("DEPRECATION") fun saveFileIntoLegacy(sourceFile: File, dstDirPath: File, outputFilename: String?, currentTimeMillis: Long): File? { // defines another name for the external media var dstFileName: String diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt index 47b19a435e..20b155d11e 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt @@ -169,11 +169,11 @@ class AttachmentsPreviewFragment : ) } - @Suppress("DEPRECATION") private fun applyInsets() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { activity?.window?.setDecorFitsSystemWindows(false) } else { + @Suppress("DEPRECATION") view?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION } ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerBottomContainer) { v, insets -> diff --git a/vector/src/main/java/im/vector/app/features/lifecycle/VectorActivityLifecycleCallbacks.kt b/vector/src/main/java/im/vector/app/features/lifecycle/VectorActivityLifecycleCallbacks.kt index 32b4bf3f12..75f02c36d7 100644 --- a/vector/src/main/java/im/vector/app/features/lifecycle/VectorActivityLifecycleCallbacks.kt +++ b/vector/src/main/java/im/vector/app/features/lifecycle/VectorActivityLifecycleCallbacks.kt @@ -92,7 +92,6 @@ class VectorActivityLifecycleCallbacks constructor(private val popupAlertManager * @return true if an app task is corrupted by a potentially malicious activity */ @SuppressLint("NewApi") - @Suppress("DEPRECATION") private suspend fun isTaskCorrupted(activity: Activity): Boolean = withContext(Dispatchers.Default) { val context = activity.applicationContext val packageManager: PackageManager = context.packageManager @@ -120,6 +119,7 @@ class VectorActivityLifecycleCallbacks constructor(private val popupAlertManager // This was present in ActivityManager.RunningTaskInfo class since API level 1! // and it is inherited from TaskInfo since Android Q (API level 29). // API 29 changes : https://developer.android.com/sdk/api_diff/29/changes/android.app.ActivityManager.RunningTaskInfo + @Suppress("DEPRECATION") manager.getRunningTasks(10).any { runningTaskInfo -> runningTaskInfo.topActivity?.let { // Check whether the activity task affinity matches with app task affinity. diff --git a/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/fallbackprompt/FallbackBiometricDialogFragment.kt b/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/fallbackprompt/FallbackBiometricDialogFragment.kt index d50ff791ed..c778e880b2 100644 --- a/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/fallbackprompt/FallbackBiometricDialogFragment.kt +++ b/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/fallbackprompt/FallbackBiometricDialogFragment.kt @@ -50,10 +50,10 @@ class FallbackBiometricDialogFragment : DialogFragment(R.layout.fragment_biometr private val parsedArgs by args() - @Suppress("DEPRECATION") override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + @Suppress("DEPRECATION") retainInstance = true setStyle(STYLE_NORMAL, android.R.style.Theme_Material_Light_Dialog) From e17f009566efde75dc02c12355a987400d763598 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 24 Aug 2022 17:54:28 +0200 Subject: [PATCH 025/187] Reduce level API check, this seems not necessary. --- .../lib/attachmentviewer/AttachmentViewerActivity.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt index 0e8590f386..ca91ddb621 100644 --- a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt +++ b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt @@ -143,12 +143,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION window.setDecorFitsSystemWindows(false) // New API instead of SYSTEM_UI_FLAG_IMMERSIVE - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE - } else { - @SuppressLint("WrongConstant") - window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE - } + window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE // New API instead of FLAG_TRANSLUCENT_STATUS window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) // new API instead of FLAG_TRANSLUCENT_NAVIGATION From 518ec738f30e515777a231e39b51bd56060ad299 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 24 Aug 2022 17:59:46 +0200 Subject: [PATCH 026/187] Reduce level API check, this seems not necessary. --- .../lib/attachmentviewer/AttachmentViewerActivity.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt index ca91ddb621..98398760d1 100644 --- a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt +++ b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt @@ -17,7 +17,6 @@ package im.vector.lib.attachmentviewer -import android.annotation.SuppressLint import android.graphics.Color import android.os.Build import android.os.Bundle @@ -352,12 +351,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi // new API instead of SYSTEM_UI_FLAG_HIDE_NAVIGATION window.decorView.windowInsetsController?.hide(WindowInsets.Type.navigationBars()) // New API instead of SYSTEM_UI_FLAG_IMMERSIVE - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE - } else { - @SuppressLint("WrongConstant") - window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE - } + window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE // New API instead of FLAG_TRANSLUCENT_STATUS window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) // New API instead of FLAG_TRANSLUCENT_NAVIGATION From cde709692899df5e9c9050869bee9d6ab26a9d56 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 24 Aug 2022 18:02:42 +0200 Subject: [PATCH 027/187] Restore this annotation --- .../android/sdk/internal/legacy/DefaultLegacySessionImporter.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt index 567f605643..7d52d9b2bf 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/legacy/DefaultLegacySessionImporter.kt @@ -104,6 +104,7 @@ internal class DefaultLegacySessionImporter @Inject constructor( } private suspend fun importCredentials(legacyConfig: LegacyHomeServerConnectionConfig) { + @Suppress("DEPRECATION") val sessionParams = SessionParams( credentials = Credentials( userId = legacyConfig.credentials.userId, From 88482c9b2edc7ea50950b24cb697d75babb836ae Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 24 Aug 2022 18:06:38 +0200 Subject: [PATCH 028/187] Reduce level API check, this seems not necessary. --- .../im/vector/app/core/platform/VectorBaseActivity.kt | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index cb8c0ec8d1..b4ba384f8f 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -16,7 +16,6 @@ package im.vector.app.core.platform -import android.annotation.SuppressLint import android.app.Activity import android.content.Context import android.os.Build @@ -469,12 +468,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION window.setDecorFitsSystemWindows(false) // New API instead of SYSTEM_UI_FLAG_IMMERSIVE - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE - } else { - @SuppressLint("WrongConstant") - window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE - } + window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE // New API instead of FLAG_TRANSLUCENT_STATUS window.statusBarColor = ContextCompat.getColor(this, im.vector.lib.attachmentviewer.R.color.half_transparent_status_bar) // New API instead of FLAG_TRANSLUCENT_NAVIGATION From 842a9bbd5595fc4901836f396f4b68047d6d99f4 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 24 Aug 2022 19:03:29 +0200 Subject: [PATCH 029/187] Add dataExtractionRules, applicable to Android 12. Exclude everything from being backed up. Also properly support Android 11. --- tools/lint/lint.xml | 1 + vector/src/main/AndroidManifest.xml | 10 +++++----- vector/src/main/res/xml/backup_rules.xml | 18 ++++++++++++++++++ .../src/main/res/xml/data_extraction_rules.xml | 17 +++++++++++++++++ 4 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 vector/src/main/res/xml/backup_rules.xml create mode 100644 vector/src/main/res/xml/data_extraction_rules.xml diff --git a/tools/lint/lint.xml b/tools/lint/lint.xml index b4b6ebc12f..1776bd341f 100644 --- a/tools/lint/lint.xml +++ b/tools/lint/lint.xml @@ -87,6 +87,7 @@ + diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index d60620dddf..c7c0d40dd7 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -318,12 +318,12 @@ - + - - - - + + + + diff --git a/vector/src/main/res/xml/backup_rules.xml b/vector/src/main/res/xml/backup_rules.xml new file mode 100644 index 0000000000..fe10b316ed --- /dev/null +++ b/vector/src/main/res/xml/backup_rules.xml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/vector/src/main/res/xml/data_extraction_rules.xml b/vector/src/main/res/xml/data_extraction_rules.xml new file mode 100644 index 0000000000..fe61eb717c --- /dev/null +++ b/vector/src/main/res/xml/data_extraction_rules.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + From c5571c06edf2145ecc13044efa248694ea77e990 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Aug 2022 09:51:32 +0200 Subject: [PATCH 030/187] Upgrade gradle plugin from 7.1.3 to 7.2.2 --- dependencies.gradle | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 8a93950c15..a402ec3135 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -7,10 +7,7 @@ ext.versions = [ 'targetCompat' : JavaVersion.VERSION_11, ] - -// Pinned to 7.1.3 because of https://github.com/vector-im/element-android/issues/6142 -// Please test carefully before upgrading again. -def gradle = "7.1.3" +def gradle = "7.2.2" // Ref: https://kotlinlang.org/releases.html def kotlin = "1.6.21" def kotlinCoroutines = "1.6.4" From 57db43c80a78bf9474abcab8ca6dc58fefc0b22a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Aug 2022 11:30:06 +0200 Subject: [PATCH 031/187] Fix gradle warning: WARNING:API 'ApkVariantOutput.getVersionCodeOverride()' is obsolete and has been replaced with 'VariantOutput.versionCode()'. --- vector-app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector-app/build.gradle b/vector-app/build.gradle index 82c433d2df..f0f1bb81b8 100644 --- a/vector-app/build.gradle +++ b/vector-app/build.gradle @@ -191,7 +191,7 @@ android { // Known limitation: it does not modify the value in the BuildConfig.java generated file // See https://issuetracker.google.com/issues/171133218 output.versionCodeOverride = baseVariantVersion + baseAbiVersionCode - print "ABI " + output.getFilter(OutputFile.ABI) + " \t-> VersionCode = " + output.versionCodeOverride + "\n" + print "ABI " + output.getFilter(OutputFile.ABI) + " \t-> VersionCode = " + output.versionCode + "\n" output.outputFileName = output.outputFileName.replace("vector-app", "vector") } } From 892484a1b306c5ff66b442ce85bf142849b37761 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 25 Aug 2022 11:54:29 +0200 Subject: [PATCH 032/187] Upgrade kotlin from 1.6.21 to 1.7.10 and dagger (+hilt) from 2.42 to 2.43.2 --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index a402ec3135..a9fe9b4eb2 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -9,9 +9,9 @@ ext.versions = [ def gradle = "7.2.2" // Ref: https://kotlinlang.org/releases.html -def kotlin = "1.6.21" +def kotlin = "1.7.10" def kotlinCoroutines = "1.6.4" -def dagger = "2.42" +def dagger = "2.43.2" def appDistribution = "16.0.0-beta04" def retrofit = "2.9.0" def arrow = "0.8.2" From 84afa4714a792d62e4506c6b4ad37b4df5b04b21 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 12 Sep 2022 17:32:42 +0200 Subject: [PATCH 033/187] App compat 1.5.1 --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index a9fe9b4eb2..b026e79768 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -48,7 +48,7 @@ ext.libs = [ ], androidx : [ 'activity' : "androidx.activity:activity:1.5.1", - 'appCompat' : "androidx.appcompat:appcompat:1.5.0", + 'appCompat' : "androidx.appcompat:appcompat:1.5.1", 'biometric' : "androidx.biometric:biometric:1.1.0", 'core' : "androidx.core:core-ktx:1.8.0", 'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1", From a1f4ffbf172315a5906c59ab821ab907d5cc2135 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 23:12:48 +0200 Subject: [PATCH 034/187] Use vanniktechEmoji "0.16.0-SNAPSHOT" --- build.gradle | 8 ++++++++ dependencies.gradle | 4 +++- dependencies_groups.gradle | 9 ++++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 49dc1e7fb4..d8de6dd55f 100644 --- a/build.gradle +++ b/build.gradle @@ -71,6 +71,14 @@ allprojects { groups.mavenCentral.group.each { includeGroup it } } } + // snapshots repository + maven { + url "https://oss.sonatype.org/content/repositories/snapshots" + content { + groups.snapshot.regex.each { includeGroupByRegex it } + groups.snapshot.group.each { includeGroup it } + } + } maven { url 'https://jitpack.io' content { diff --git a/dependencies.gradle b/dependencies.gradle index b026e79768..fd758dd859 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -25,7 +25,9 @@ def mavericks = "2.7.0" def glide = "4.13.2" def bigImageViewer = "1.8.1" def jjwt = "0.11.5" -def vanniktechEmoji = "0.15.0" +// Temporary version to unblock #6929. Once 0.16.0 is released we should use it, and revert +// the whole commit which set version 0.16.0-SNAPSHOT +def vanniktechEmoji = "0.16.0-SNAPSHOT" def fragment = "1.5.2" diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle index 433bc53568..e44e0bc5c2 100644 --- a/dependencies_groups.gradle +++ b/dependencies_groups.gradle @@ -38,6 +38,13 @@ ext.groups = [ 'com.google.testing.platform', ] ], + snapshot: [ + regex: [ + ], + group: [ + 'com.vanniktech', + ] + ], mavenCentral: [ regex: [ ], @@ -118,7 +125,7 @@ ext.groups = [ 'com.sun.xml.bind.mvn', 'com.sun.xml.fastinfoset', 'com.thoughtworks.qdox', - 'com.vanniktech', + // 'com.vanniktech', 'commons-cli', 'commons-codec', 'commons-io', From d4eb619d4022f7e4be139e164df746693d2de812 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 23:30:20 +0200 Subject: [PATCH 035/187] Changelog --- changelog.d/6929.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/6929.misc diff --git a/changelog.d/6929.misc b/changelog.d/6929.misc new file mode 100644 index 0000000000..d12167cfea --- /dev/null +++ b/changelog.d/6929.misc @@ -0,0 +1 @@ +Target API 12 and compile with Android SDK 32. From c91ba06285419c2122ce2c7fa539531593e9bb4c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 19 Sep 2022 10:50:15 +0200 Subject: [PATCH 036/187] Fix lint warnings, some code has vanished dur to the rebasing of the branch... --- vector-app/src/main/AndroidManifest.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vector-app/src/main/AndroidManifest.xml b/vector-app/src/main/AndroidManifest.xml index bff594c0de..2767b20404 100644 --- a/vector-app/src/main/AndroidManifest.xml +++ b/vector-app/src/main/AndroidManifest.xml @@ -6,6 +6,8 @@ Date: Mon, 19 Sep 2022 11:56:40 +0200 Subject: [PATCH 037/187] Move xml resource in the module where they are used to avoid lint false positive `UnusedResources` issues. --- {vector => vector-app}/src/main/res/xml/backup_rules.xml | 0 {vector => vector-app}/src/main/res/xml/data_extraction_rules.xml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {vector => vector-app}/src/main/res/xml/backup_rules.xml (100%) rename {vector => vector-app}/src/main/res/xml/data_extraction_rules.xml (100%) diff --git a/vector/src/main/res/xml/backup_rules.xml b/vector-app/src/main/res/xml/backup_rules.xml similarity index 100% rename from vector/src/main/res/xml/backup_rules.xml rename to vector-app/src/main/res/xml/backup_rules.xml diff --git a/vector/src/main/res/xml/data_extraction_rules.xml b/vector-app/src/main/res/xml/data_extraction_rules.xml similarity index 100% rename from vector/src/main/res/xml/data_extraction_rules.xml rename to vector-app/src/main/res/xml/data_extraction_rules.xml From 740b69d48cd69543147c22977dc77fe040a5df07 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 19 Sep 2022 13:42:30 +0300 Subject: [PATCH 038/187] Make other sessions view dynamic. --- .../v2/VectorSettingsDevicesFragment.kt | 8 +++++- .../v2/VectorSettingsDevicesViewNavigator.kt | 12 ++++++-- .../v2/othersessions/OtherSessionsActivity.kt | 16 +++++++++-- .../v2/othersessions/OtherSessionsArgs.kt | 28 +++++++++++++++++++ .../v2/othersessions/OtherSessionsFragment.kt | 7 +++++ 5 files changed, 65 insertions(+), 6 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsArgs.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt index 1e91384c3a..f4725d5571 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -37,6 +37,7 @@ import im.vector.app.core.resources.DrawableProvider import im.vector.app.databinding.FragmentSettingsDevicesBinding import im.vector.app.features.crypto.recover.SetupMode import im.vector.app.features.crypto.verification.VerificationBottomSheet +import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.list.NUMBER_OF_OTHER_DEVICES_TO_RENDER import im.vector.app.features.settings.devices.v2.list.OtherSessionsView import im.vector.app.features.settings.devices.v2.list.SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS @@ -260,6 +261,11 @@ class VectorSettingsDevicesFragment : } override fun onViewAllOtherSessionsClicked() { - viewNavigator.navigateToOtherSessions(requireActivity()) + viewNavigator.navigateToOtherSessions( + context = requireActivity(), + titleResourceId = R.string.device_manager_sessions_other_title, + defaultFilter = DeviceManagerFilterType.ALL_SESSIONS, + includeCurrentSession = false + ) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt index 486785c918..991de805e7 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt @@ -17,6 +17,7 @@ package im.vector.app.features.settings.devices.v2 import android.content.Context +import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.othersessions.OtherSessionsActivity import im.vector.app.features.settings.devices.v2.overview.SessionOverviewActivity import javax.inject.Inject @@ -27,7 +28,14 @@ class VectorSettingsDevicesViewNavigator @Inject constructor() { context.startActivity(SessionOverviewActivity.newIntent(context, deviceId)) } - fun navigateToOtherSessions(context: Context) { - context.startActivity(OtherSessionsActivity.newIntent(context)) + fun navigateToOtherSessions( + context: Context, + titleResourceId: Int, + defaultFilter: DeviceManagerFilterType, + includeCurrentSession: Boolean, + ) { + context.startActivity( + OtherSessionsActivity.newIntent(context, titleResourceId, defaultFilter, includeCurrentSession) + ) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsActivity.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsActivity.kt index b9ab59d8f5..a2c9da6ea0 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsActivity.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsActivity.kt @@ -20,9 +20,11 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.view.View +import com.airbnb.mvrx.Mavericks import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.SimpleFragmentActivity +import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType @AndroidEntryPoint class OtherSessionsActivity : SimpleFragmentActivity() { @@ -35,14 +37,22 @@ class OtherSessionsActivity : SimpleFragmentActivity() { if (isFirstCreation()) { addFragment( container = views.container, - fragmentClass = OtherSessionsFragment::class.java + fragmentClass = OtherSessionsFragment::class.java, + params = intent.getParcelableExtra(Mavericks.KEY_ARG) ) } } companion object { - fun newIntent(context: Context): Intent { - return Intent(context, OtherSessionsActivity::class.java) + fun newIntent( + context: Context, + titleResourceId: Int, + defaultFilter: DeviceManagerFilterType, + includeCurrentSession: Boolean, + ): Intent { + return Intent(context, OtherSessionsActivity::class.java).apply { + putExtra(Mavericks.KEY_ARG, OtherSessionsArgs(titleResourceId, defaultFilter, includeCurrentSession)) + } } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsArgs.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsArgs.kt new file mode 100644 index 0000000000..55a7000c4f --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsArgs.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.othersessions + +import android.os.Parcelable +import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType +import kotlinx.parcelize.Parcelize + +@Parcelize +data class OtherSessionsArgs( + val titleResourceId: Int, + val defaultFilter: DeviceManagerFilterType, + val includeCurrentSession: Boolean, +) : Parcelable diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt index 81ea5f4b89..26cd74a380 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt @@ -22,6 +22,7 @@ import android.view.View import android.view.ViewGroup import androidx.core.view.isVisible import com.airbnb.mvrx.Success +import com.airbnb.mvrx.args import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import dagger.hilt.android.AndroidEntryPoint @@ -46,6 +47,7 @@ class OtherSessionsFragment : OtherSessionsView.Callback { private val viewModel: OtherSessionsViewModel by fragmentViewModel() + private val args: OtherSessionsArgs by args() @Inject lateinit var colorProvider: ColorProvider @@ -57,6 +59,7 @@ class OtherSessionsFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + views.otherSessionsToolbar.title = getString(args.titleResourceId) setupToolbar(views.otherSessionsToolbar).allowBack() observeViewEvents() initFilterView() @@ -85,6 +88,10 @@ class OtherSessionsFragment : } views.deviceListOtherSessions.callback = this + + if (args.defaultFilter != DeviceManagerFilterType.ALL_SESSIONS) { + viewModel.handle(OtherSessionsAction.FilterDevices(args.defaultFilter)) + } } override fun onBottomSheetResult(resultCode: Int, data: Any?) { From 7db222af0c59f2f27acbed2ce21ed5cd1412d1d1 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 19 Sep 2022 15:37:13 +0300 Subject: [PATCH 039/187] Render security recommendation sessions. --- .../src/main/res/values/strings.xml | 1 + .../settings/devices/v2/DeviceFullInfo.kt | 1 + .../v2/VectorSettingsDevicesFragment.kt | 25 +++++++++++++ .../devices/v2/list/OtherSessionItem.kt | 8 +++++ .../v2/list/OtherSessionsController.kt | 36 ++++++++++++------- .../v2/list/SecurityRecommendationView.kt | 9 +++++ .../othersessions/OtherSessionsViewModel.kt | 4 +-- .../othersessions/OtherSessionsViewState.kt | 6 +++- .../v2/overview/GetDeviceFullInfoUseCase.kt | 4 ++- 9 files changed, 78 insertions(+), 16 deletions(-) diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 714b48e8b4..82e2177581 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3246,6 +3246,7 @@ Verified · Last activity %1$s Unverified · Last activity %1$s + Unverified · Your current session Inactive for %1$d+ day (%2$s) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt index f0a91c6183..373df53b1b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DeviceFullInfo.kt @@ -25,4 +25,5 @@ data class DeviceFullInfo( val cryptoDeviceInfo: CryptoDeviceInfo?, val roomEncryptionTrustLevel: RoomEncryptionTrustLevel, val isInactive: Boolean, + val isCurrentDevice: Boolean, ) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt index f4725d5571..da1a9a2fbd 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -41,6 +41,7 @@ import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.list.NUMBER_OF_OTHER_DEVICES_TO_RENDER import im.vector.app.features.settings.devices.v2.list.OtherSessionsView import im.vector.app.features.settings.devices.v2.list.SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS +import im.vector.app.features.settings.devices.v2.list.SecurityRecommendationView import im.vector.app.features.settings.devices.v2.list.SecurityRecommendationViewState import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState import javax.inject.Inject @@ -84,6 +85,7 @@ class VectorSettingsDevicesFragment : initLearnMoreButtons() initWaitingView() initOtherSessionsView() + initSecurityRecommendationsView() observeViewEvents() } @@ -126,6 +128,29 @@ class VectorSettingsDevicesFragment : views.deviceListOtherSessions.callback = this } + private fun initSecurityRecommendationsView() { + views.deviceListUnverifiedSessionsRecommendation.callback = object : SecurityRecommendationView.Callback { + override fun onViewAllClicked() { + viewNavigator.navigateToOtherSessions( + requireActivity(), + R.string.device_manager_header_section_security_recommendations_title, + DeviceManagerFilterType.UNVERIFIED, + includeCurrentSession = true + ) + } + } + views.deviceListInactiveSessionsRecommendation.callback = object : SecurityRecommendationView.Callback { + override fun onViewAllClicked() { + viewNavigator.navigateToOtherSessions( + requireActivity(), + R.string.device_manager_header_section_security_recommendations_title, + DeviceManagerFilterType.INACTIVE, + includeCurrentSession = true + ) + } + } + } + override fun onDestroyView() { cleanUpLearnMoreButtonsListeners() super.onDestroyView() diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionItem.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionItem.kt index c73389d775..283e64fffe 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionItem.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionItem.kt @@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices.v2.list import android.graphics.drawable.Drawable import android.widget.ImageView import android.widget.TextView +import androidx.annotation.ColorInt import com.airbnb.epoxy.EpoxyAttribute import com.airbnb.epoxy.EpoxyModelClass import im.vector.app.R @@ -45,6 +46,10 @@ abstract class OtherSessionItem : VectorEpoxyModel(R.la @EpoxyAttribute var sessionDescription: String? = null + @EpoxyAttribute + @ColorInt + var sessionDescriptionColor: Int? = null + @EpoxyAttribute var sessionDescriptionDrawable: Drawable? = null @@ -82,6 +87,9 @@ abstract class OtherSessionItem : VectorEpoxyModel(R.la holder.otherSessionVerificationStatusImageView.render(roomEncryptionTrustLevel) holder.otherSessionNameTextView.text = sessionName holder.otherSessionDescriptionTextView.text = sessionDescription + sessionDescriptionColor?.let { + holder.otherSessionDescriptionTextView.setTextColor(it) + } holder.otherSessionDescriptionTextView.setCompoundDrawablesWithIntrinsicBounds(sessionDescriptionDrawable, null, null, null) } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt index 06f3373f61..bcf6e87575 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt @@ -53,20 +53,14 @@ class OtherSessionsController @Inject constructor( data.forEach { device -> val dateFormatKind = if (device.isInactive) DateFormatKind.TIMELINE_DAY_DIVIDER else DateFormatKind.DEFAULT_DATE_AND_TIME val formattedLastActivityDate = host.dateFormatter.format(device.deviceInfo.lastSeenTs, dateFormatKind) - val description = if (device.isInactive) { - stringProvider.getQuantityString( - R.plurals.device_manager_other_sessions_description_inactive, - SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS, - SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS, - formattedLastActivityDate - ) - } else if (device.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Trusted) { - stringProvider.getString(R.string.device_manager_other_sessions_description_verified, formattedLastActivityDate) + val description = calculateDescription(device, formattedLastActivityDate) + val descriptionColor = if (device.isCurrentDevice) { + host.colorProvider.getColorFromAttribute(R.attr.colorError) } else { - stringProvider.getString(R.string.device_manager_other_sessions_description_unverified, formattedLastActivityDate) + host.colorProvider.getColorFromAttribute(R.attr.vctr_content_secondary) } - val drawableColor = colorProvider.getColorFromAttribute(R.attr.vctr_content_secondary) - val descriptionDrawable = if (device.isInactive) drawableProvider.getDrawable(R.drawable.ic_inactive_sessions, drawableColor) else null + val drawableColor = host.colorProvider.getColorFromAttribute(R.attr.vctr_content_secondary) + val descriptionDrawable = if (device.isInactive) host.drawableProvider.getDrawable(R.drawable.ic_inactive_sessions, drawableColor) else null otherSessionItem { id(device.deviceInfo.deviceId) @@ -75,10 +69,28 @@ class OtherSessionsController @Inject constructor( sessionName(device.deviceInfo.displayName) sessionDescription(description) sessionDescriptionDrawable(descriptionDrawable) + sessionDescriptionColor(descriptionColor) stringProvider(this@OtherSessionsController.stringProvider) clickListener { device.deviceInfo.deviceId?.let { host.callback?.onItemClicked(it) } } } } } } + + private fun calculateDescription(device: DeviceFullInfo, formattedLastActivityDate: String): String { + return if (device.isInactive) { + stringProvider.getQuantityString( + R.plurals.device_manager_other_sessions_description_inactive, + SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS, + SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS, + formattedLastActivityDate + ) + } else if (device.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Trusted) { + stringProvider.getString(R.string.device_manager_other_sessions_description_verified, formattedLastActivityDate) + } else if (device.isCurrentDevice) { + stringProvider.getString(R.string.device_manager_other_sessions_description_unverified_current_session) + } else { + stringProvider.getString(R.string.device_manager_other_sessions_description_unverified, formattedLastActivityDate) + } + } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SecurityRecommendationView.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SecurityRecommendationView.kt index 93cf3c0501..c4d86af8c3 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SecurityRecommendationView.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SecurityRecommendationView.kt @@ -31,7 +31,12 @@ class SecurityRecommendationView @JvmOverloads constructor( defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr) { + interface Callback { + fun onViewAllClicked() + } + private val views: ViewSecurityRecommendationBinding + var callback: Callback? = null init { inflate(context, R.layout.view_security_recommendation, this) @@ -47,6 +52,10 @@ class SecurityRecommendationView @JvmOverloads constructor( setDescription(it) setImage(it) } + + views.recommendationViewAllButton.setOnClickListener { + callback?.onViewAllClicked() + } } private fun setTitle(typedArray: TypedArray) { diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt index a40d95c6d9..2ca24dd92a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt @@ -30,7 +30,7 @@ import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import kotlinx.coroutines.Job class OtherSessionsViewModel @AssistedInject constructor( - @Assisted initialState: OtherSessionsViewState, + @Assisted private val initialState: OtherSessionsViewState, activeSessionHolder: ActiveSessionHolder, private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase, refreshDevicesUseCase: RefreshDevicesUseCase @@ -55,7 +55,7 @@ class OtherSessionsViewModel @AssistedInject constructor( observeDevicesJob?.cancel() observeDevicesJob = getDeviceFullInfoListUseCase.execute( filterType = currentFilter, - excludeCurrentDevice = true + excludeCurrentDevice = !initialState.includeCurrentSession ) .execute { async -> copy( diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewState.kt index d03cba03f9..cb30490845 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewState.kt @@ -25,4 +25,8 @@ import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType data class OtherSessionsViewState( val devices: Async> = Uninitialized, val currentFilter: DeviceManagerFilterType = DeviceManagerFilterType.ALL_SESSIONS, -) : MavericksState + val includeCurrentSession: Boolean = false, +) : MavericksState { + + constructor(args: OtherSessionsArgs) : this(includeCurrentSession = args.includeCurrentSession) +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt index 5a8106f2fd..72a48238b0 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt @@ -48,11 +48,13 @@ class GetDeviceFullInfoUseCase @Inject constructor( val fullInfo = if (info != null && cryptoInfo != null) { val roomEncryptionTrustLevel = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoInfo) val isInactive = checkIfSessionIsInactiveUseCase.execute(info.lastSeenTs ?: 0) + val isCurrentDevice = currentSessionCrossSigningInfo.deviceId == cryptoInfo.deviceId DeviceFullInfo( deviceInfo = info, cryptoDeviceInfo = cryptoInfo, roomEncryptionTrustLevel = roomEncryptionTrustLevel, - isInactive = isInactive + isInactive = isInactive, + isCurrentDevice = isCurrentDevice, ) } else { null From ec9843fb53d4b672ee66832cf3fbac5c3b62dc2c Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 19 Sep 2022 15:38:02 +0300 Subject: [PATCH 040/187] Fix unverified session detection logic. --- .../app/features/settings/devices/v2/DevicesViewModel.kt | 2 +- .../settings/devices/v2/GetDeviceFullInfoListUseCase.kt | 3 ++- .../settings/devices/v2/filter/FilterDevicesUseCase.kt | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt index 9c1b70a7e2..465e3bb7b8 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt @@ -71,7 +71,7 @@ class DevicesViewModel @AssistedInject constructor( .execute { async -> if (async is Success) { val deviceFullInfoList = async.invoke() - val unverifiedSessionsCount = deviceFullInfoList.count { !it.cryptoDeviceInfo?.isVerified.orFalse() } + val unverifiedSessionsCount = deviceFullInfoList.count { !it.cryptoDeviceInfo?.trustLevel?.isCrossSigningVerified().orFalse() } val inactiveSessionsCount = deviceFullInfoList.count { it.isInactive } copy( devices = async, diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCase.kt index 3c0d3a5e56..b7b2572d20 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCase.kt @@ -68,7 +68,8 @@ class GetDeviceFullInfoListUseCase @Inject constructor( val cryptoDeviceInfo = cryptoList.firstOrNull { it.deviceId == deviceInfo.deviceId } val roomEncryptionTrustLevel = getEncryptionTrustLevelForDeviceUseCase.execute(currentSessionCrossSigningInfo, cryptoDeviceInfo) val isInactive = checkIfSessionIsInactiveUseCase.execute(deviceInfo.lastSeenTs ?: 0) - DeviceFullInfo(deviceInfo, cryptoDeviceInfo, roomEncryptionTrustLevel, isInactive) + val isCurrentDevice = currentSessionCrossSigningInfo.deviceId == cryptoDeviceInfo?.deviceId + DeviceFullInfo(deviceInfo, cryptoDeviceInfo, roomEncryptionTrustLevel, isInactive, isCurrentDevice) } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/filter/FilterDevicesUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/filter/FilterDevicesUseCase.kt index e0bb567dc6..a23a7a7108 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/filter/FilterDevicesUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/filter/FilterDevicesUseCase.kt @@ -31,8 +31,8 @@ class FilterDevicesUseCase @Inject constructor() { .filter { when (filterType) { DeviceManagerFilterType.ALL_SESSIONS -> true - DeviceManagerFilterType.VERIFIED -> it.cryptoDeviceInfo?.isVerified.orFalse() - DeviceManagerFilterType.UNVERIFIED -> !it.cryptoDeviceInfo?.isVerified.orFalse() + DeviceManagerFilterType.VERIFIED -> it.cryptoDeviceInfo?.trustLevel?.isCrossSigningVerified().orFalse() + DeviceManagerFilterType.UNVERIFIED -> !it.cryptoDeviceInfo?.trustLevel?.isCrossSigningVerified().orFalse() DeviceManagerFilterType.INACTIVE -> it.isInactive } } From 2ad0cd46bb75d136513a26750258f5cac74a3866 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 19 Sep 2022 16:18:30 +0300 Subject: [PATCH 041/187] Fix unit tests. --- .../settings/devices/v2/DevicesViewModelTest.kt | 6 ++++-- .../devices/v2/GetDeviceFullInfoListUseCaseTest.kt | 10 +++++++--- .../v2/VectorSettingsDevicesViewNavigatorTest.kt | 11 +++++++---- .../devices/v2/filter/FilterDevicesUseCaseTest.kt | 12 ++++++++---- .../v2/overview/GetDeviceFullInfoUseCaseTest.kt | 2 ++ 5 files changed, 28 insertions(+), 13 deletions(-) diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt index 351d6b8eb0..741fb15cc3 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt @@ -171,13 +171,15 @@ class DevicesViewModelTest { deviceInfo = mockk(), cryptoDeviceInfo = verifiedCryptoDeviceInfo, roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted, - isInactive = false + isInactive = false, + isCurrentDevice = true ) val deviceFullInfo2 = DeviceFullInfo( deviceInfo = mockk(), cryptoDeviceInfo = unverifiedCryptoDeviceInfo, roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning, - isInactive = true + isInactive = true, + isCurrentDevice = false ) val deviceFullInfoList = listOf(deviceFullInfo1, deviceFullInfo2) val deviceFullInfoListFlow = flowOf(deviceFullInfoList) diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCaseTest.kt index 54b160f196..89516745bf 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCaseTest.kt @@ -106,19 +106,22 @@ class GetDeviceFullInfoListUseCaseTest { deviceInfo = deviceInfo1, cryptoDeviceInfo = cryptoDeviceInfo1, roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted, - isInactive = true + isInactive = true, + isCurrentDevice = true ) val expectedResult2 = DeviceFullInfo( deviceInfo = deviceInfo2, cryptoDeviceInfo = cryptoDeviceInfo2, roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted, - isInactive = false + isInactive = false, + isCurrentDevice = false ) val expectedResult3 = DeviceFullInfo( deviceInfo = deviceInfo3, cryptoDeviceInfo = cryptoDeviceInfo3, roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning, - isInactive = false + isInactive = false, + isCurrentDevice = false ) val expectedResult = listOf(expectedResult3, expectedResult2, expectedResult1) every { filterDevicesUseCase.execute(any(), any()) } returns expectedResult @@ -160,6 +163,7 @@ class GetDeviceFullInfoListUseCaseTest { private fun givenCurrentSessionCrossSigningInfo(): CurrentSessionCrossSigningInfo { val currentSessionCrossSigningInfo = mockk() every { getCurrentSessionCrossSigningInfoUseCase.execute() } returns flowOf(currentSessionCrossSigningInfo) + every { currentSessionCrossSigningInfo.deviceId } returns A_DEVICE_ID_1 return currentSessionCrossSigningInfo } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigatorTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigatorTest.kt index a1f0918b31..7b8b6ee82d 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigatorTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigatorTest.kt @@ -17,6 +17,7 @@ package im.vector.app.features.settings.devices.v2 import android.content.Intent +import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.othersessions.OtherSessionsActivity import im.vector.app.features.settings.devices.v2.overview.SessionOverviewActivity import im.vector.app.test.fakes.FakeContext @@ -30,6 +31,8 @@ import org.junit.Before import org.junit.Test private const val A_SESSION_ID = "session_id" +private const val A_TITLE_RESOURCE_ID = 1234 +private val A_DEFAULT_FILTER = DeviceManagerFilterType.INACTIVE class VectorSettingsDevicesViewNavigatorTest { @@ -61,10 +64,10 @@ class VectorSettingsDevicesViewNavigatorTest { @Test fun `given an intent when navigating to other sessions list then it starts the correct activity`() { - val intent = givenIntentForOtherSessions() + val intent = givenIntentForOtherSessions(A_TITLE_RESOURCE_ID, A_DEFAULT_FILTER, true) context.givenStartActivity(intent) - vectorSettingsDevicesViewNavigator.navigateToOtherSessions(context.instance) + vectorSettingsDevicesViewNavigator.navigateToOtherSessions(context.instance, A_TITLE_RESOURCE_ID, A_DEFAULT_FILTER, true) verify { context.instance.startActivity(intent) @@ -77,9 +80,9 @@ class VectorSettingsDevicesViewNavigatorTest { return intent } - private fun givenIntentForOtherSessions(): Intent { + private fun givenIntentForOtherSessions(titleResourceId: Int, defaultFilter: DeviceManagerFilterType, includeCurrentSession: Boolean): Intent { val intent = mockk() - every { OtherSessionsActivity.newIntent(context.instance) } returns intent + every { OtherSessionsActivity.newIntent(context.instance, titleResourceId, defaultFilter, includeCurrentSession) } returns intent return intent } } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/filter/FilterDevicesUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/filter/FilterDevicesUseCaseTest.kt index 1254e2a80a..2bb5168190 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/filter/FilterDevicesUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/filter/FilterDevicesUseCaseTest.kt @@ -33,7 +33,8 @@ private val activeVerifiedDevice = DeviceFullInfo( trustLevel = DeviceTrustLevel(crossSigningVerified = true, locallyVerified = true) ), roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted, - isInactive = false + isInactive = false, + isCurrentDevice = true ) private val inactiveVerifiedDevice = DeviceFullInfo( deviceInfo = DeviceInfo(deviceId = "INACTIVE_VERIFIED_DEVICE"), @@ -43,7 +44,8 @@ private val inactiveVerifiedDevice = DeviceFullInfo( trustLevel = DeviceTrustLevel(crossSigningVerified = true, locallyVerified = true) ), roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Trusted, - isInactive = true + isInactive = true, + isCurrentDevice = false ) private val activeUnverifiedDevice = DeviceFullInfo( deviceInfo = DeviceInfo(deviceId = "ACTIVE_UNVERIFIED_DEVICE"), @@ -53,7 +55,8 @@ private val activeUnverifiedDevice = DeviceFullInfo( trustLevel = DeviceTrustLevel(crossSigningVerified = false, locallyVerified = false) ), roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning, - isInactive = false + isInactive = false, + isCurrentDevice = false ) private val inactiveUnverifiedDevice = DeviceFullInfo( deviceInfo = DeviceInfo(deviceId = "INACTIVE_UNVERIFIED_DEVICE"), @@ -63,7 +66,8 @@ private val inactiveUnverifiedDevice = DeviceFullInfo( trustLevel = DeviceTrustLevel(crossSigningVerified = false, locallyVerified = false) ), roomEncryptionTrustLevel = RoomEncryptionTrustLevel.Warning, - isInactive = true + isInactive = true, + isCurrentDevice = false ) private val devices = listOf( diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt index 9c7515f2da..16cb925e6e 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt @@ -85,6 +85,7 @@ class GetDeviceFullInfoUseCaseTest { fakeActiveSessionHolder.fakeSession.fakeCryptoService.cryptoDeviceInfoWithIdLiveData.givenAsFlow() val trustLevel = givenTrustLevel(currentSessionCrossSigningInfo, cryptoDeviceInfo) val isInactive = false + val isCurrentDevice = true every { checkIfSessionIsInactiveUseCase.execute(any()) } returns isInactive // When @@ -96,6 +97,7 @@ class GetDeviceFullInfoUseCaseTest { cryptoDeviceInfo = cryptoDeviceInfo, roomEncryptionTrustLevel = trustLevel, isInactive = isInactive, + isCurrentDevice = isCurrentDevice ) verify { fakeActiveSessionHolder.instance.getSafeActiveSession() } verify { getCurrentSessionCrossSigningInfoUseCase.execute() } From 72cc0deda2b6c25d4c2d7307e4a7bc4e6b5700e9 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 19 Sep 2022 16:45:52 +0300 Subject: [PATCH 042/187] Add changelog. --- changelog.d/7170.wip | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7170.wip diff --git a/changelog.d/7170.wip b/changelog.d/7170.wip new file mode 100644 index 0000000000..f5b71a14f8 --- /dev/null +++ b/changelog.d/7170.wip @@ -0,0 +1 @@ +[Device Manager] Unverified and inactive sessions list From 81beccdd8e8d123106c581230166a2729e6526e4 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 14 Sep 2022 10:59:29 +0200 Subject: [PATCH 043/187] Adding changelog entry --- changelog.d/7114.wip | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7114.wip diff --git a/changelog.d/7114.wip b/changelog.d/7114.wip new file mode 100644 index 0000000000..d5bd584feb --- /dev/null +++ b/changelog.d/7114.wip @@ -0,0 +1 @@ +[Device management] Verify a session From 5759a0f7da39c55dc4507e8da6508fb66309d43e Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 14 Sep 2022 11:14:53 +0200 Subject: [PATCH 044/187] Adding click listeners on verify button --- .../settings/devices/v2/VectorSettingsDevicesFragment.kt | 3 +++ .../features/settings/devices/v2/list/SessionInfoView.kt | 1 + .../devices/v2/overview/SessionOverviewFragment.kt | 7 +++++++ 3 files changed, 11 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt index 1e91384c3a..01d87b4142 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -227,6 +227,9 @@ class VectorSettingsDevicesFragment : views.deviceListCurrentSession.viewDetailsButton.debouncedClicks { currentDeviceInfo.deviceInfo.deviceId?.let { deviceId -> navigateToSessionOverview(deviceId) } } + views.deviceListCurrentSession.viewVerifyButton.debouncedClicks { + // TODO show bottom Sheet verification process + } } ?: run { hideCurrentSessionView() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt index 555d216dfc..38bc0cb5d8 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt @@ -49,6 +49,7 @@ class SessionInfoView @JvmOverloads constructor( } val viewDetailsButton = views.sessionInfoViewDetailsButton + val viewVerifyButton = views.sessionInfoVerifySessionButton fun render( sessionInfoViewState: SessionInfoViewState, diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index 3fea7a9316..ed8ec1a55f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -81,6 +81,7 @@ class SessionOverviewFragment : override fun invalidate() = withState(viewModel) { state -> updateToolbar(state.isCurrentSession) + updateVerifyButton() updateEntryDetails(state.deviceId) if (state.deviceInfo is Success) { renderSessionInfo(state.isCurrentSession, state.deviceInfo.invoke()) @@ -96,6 +97,12 @@ class SessionOverviewFragment : ?.setTitle(titleResId) } + private fun updateVerifyButton() { + views.sessionOverviewInfo.viewVerifyButton.debouncedClicks { + // TODO show bottom Sheet verification process + } + } + private fun updateEntryDetails(deviceId: String) { views.sessionOverviewEntryDetails.setOnClickListener { viewNavigator.navigateToSessionDetails(requireContext(), deviceId) From 8cd7b0744ae3db7f945220141223639cb64717a6 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 14 Sep 2022 15:50:11 +0200 Subject: [PATCH 045/187] Verification process for the current Session --- .../settings/devices/v2/DevicesAction.kt | 1 + .../settings/devices/v2/DevicesViewModel.kt | 17 +++++++ .../v2/VectorSettingsDevicesFragment.kt | 2 +- ...eckIfCurrentSessionCanBeVerifiedUseCase.kt | 48 +++++++++++++++++++ 4 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesAction.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesAction.kt index 8c7718bfcf..c7437db44c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesAction.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesAction.kt @@ -20,5 +20,6 @@ import im.vector.app.core.platform.VectorViewModelAction import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo sealed class DevicesAction : VectorViewModelAction { + object VerifyCurrentSession : DevicesAction() data class MarkAsManuallyVerified(val cryptoDeviceInfo: CryptoDeviceInfo) : DevicesAction() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt index 9c1b70a7e2..44dc599765 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt @@ -25,6 +25,7 @@ import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType +import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch @@ -37,6 +38,7 @@ class DevicesViewModel @AssistedInject constructor( private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase, private val refreshDevicesOnCryptoDevicesChangeUseCase: RefreshDevicesOnCryptoDevicesChangeUseCase, refreshDevicesUseCase: RefreshDevicesUseCase, + private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, ) : VectorSessionsListViewModel(initialState, activeSessionHolder, refreshDevicesUseCase) { @AssistedFactory @@ -94,10 +96,25 @@ class DevicesViewModel @AssistedInject constructor( override fun handle(action: DevicesAction) { when (action) { + is DevicesAction.VerifyCurrentSession -> handleVerifyCurrentSessionAction() is DevicesAction.MarkAsManuallyVerified -> handleMarkAsManuallyVerifiedAction() } } + // TODO add unit tests + private fun handleVerifyCurrentSessionAction() { + viewModelScope.launch { + val currentSessionCanBeVerified = checkIfCurrentSessionCanBeVerifiedUseCase.execute() + if (currentSessionCanBeVerified) { + activeSessionHolder.getSafeActiveSession()?.let { session -> + _viewEvents.post(DevicesViewEvent.SelfVerification(session)) + } + } else { + _viewEvents.post(DevicesViewEvent.PromptResetSecrets) + } + } + } + private fun handleMarkAsManuallyVerifiedAction() { // TODO implement when needed } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt index 01d87b4142..3713357b19 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -228,7 +228,7 @@ class VectorSettingsDevicesFragment : currentDeviceInfo.deviceInfo.deviceId?.let { deviceId -> navigateToSessionOverview(deviceId) } } views.deviceListCurrentSession.viewVerifyButton.debouncedClicks { - // TODO show bottom Sheet verification process + viewModel.handle(DevicesAction.VerifyCurrentSession) } } ?: run { hideCurrentSessionView() diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt new file mode 100644 index 0000000000..36e4e981df --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.verification + +import im.vector.app.core.di.ActiveSessionHolder +import kotlinx.coroutines.flow.firstOrNull +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.flow.flow +import timber.log.Timber +import javax.inject.Inject + +// TODO add unit tests +class CheckIfCurrentSessionCanBeVerifiedUseCase @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, +) { + + suspend fun execute(): Boolean { + val session = activeSessionHolder.getSafeActiveSession() + val cryptoSessionsCount = session?.flow() + ?.liveUserCryptoDevices(session.myUserId) + ?.firstOrNull() + ?.size + ?: 0 + val hasOtherSessions = cryptoSessionsCount > 1 + + val isRecoverySetup = session + ?.sharedSecretStorageService() + ?.isRecoverySetup() + .orFalse() + + Timber.d("hasOtherSessions=$hasOtherSessions (otherSessionsCount=$cryptoSessionsCount), isRecoverySetup=$isRecoverySetup") + return hasOtherSessions || isRecoverySetup + } +} From d8263277731ded17ac8fb1fff9135aef5d413f28 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 14 Sep 2022 17:08:27 +0200 Subject: [PATCH 046/187] Adding unit tests for CheckIfCurrentSessionCanBeVerifiedUseCase --- ...eckIfCurrentSessionCanBeVerifiedUseCase.kt | 1 - .../devices/v2/DevicesViewModelTest.kt | 3 + ...fCurrentSessionCanBeVerifiedUseCaseTest.kt | 124 ++++++++++++++++++ .../fakes/FakeSharedSecretStorageService.kt | 8 +- 4 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCaseTest.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt index 36e4e981df..3fdef1a98f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCase.kt @@ -23,7 +23,6 @@ import org.matrix.android.sdk.flow.flow import timber.log.Timber import javax.inject.Inject -// TODO add unit tests class CheckIfCurrentSessionCanBeVerifiedUseCase @Inject constructor( private val activeSessionHolder: ActiveSessionHolder, ) { diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt index 351d6b8eb0..d9a64c82ef 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt @@ -18,6 +18,7 @@ package im.vector.app.features.settings.devices.v2 import com.airbnb.mvrx.Success import com.airbnb.mvrx.test.MvRxTestRule +import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeVerificationService import im.vector.app.test.test @@ -45,6 +46,7 @@ class DevicesViewModelTest { private val getDeviceFullInfoListUseCase = mockk() private val refreshDevicesUseCase = mockk() private val refreshDevicesOnCryptoDevicesChangeUseCase = mockk() + private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk() private fun createViewModel(): DevicesViewModel { return DevicesViewModel( @@ -54,6 +56,7 @@ class DevicesViewModelTest { getDeviceFullInfoListUseCase, refreshDevicesOnCryptoDevicesChangeUseCase, refreshDevicesUseCase, + checkIfCurrentSessionCanBeVerifiedUseCase, ) } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCaseTest.kt new file mode 100644 index 0000000000..22bc0edae1 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/CheckIfCurrentSessionCanBeVerifiedUseCaseTest.kt @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.verification + +import im.vector.app.test.fakes.FakeActiveSessionHolder +import io.mockk.every +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.unmockkAll +import io.mockk.verify +import kotlinx.coroutines.flow.flowOf +import kotlinx.coroutines.test.runTest +import org.amshove.kluent.shouldBeEqualTo +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo +import org.matrix.android.sdk.flow.FlowSession +import org.matrix.android.sdk.flow.flow + +class CheckIfCurrentSessionCanBeVerifiedUseCaseTest { + + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + + private val checkIfCurrentSessionCanBeVerifiedUseCase = CheckIfCurrentSessionCanBeVerifiedUseCase( + activeSessionHolder = fakeActiveSessionHolder.instance + ) + + @Before + fun setUp() { + mockkStatic("org.matrix.android.sdk.flow.FlowSessionKt") + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `given there are other sessions when checking if session can be verified then result is true`() = runTest { + // Given + val device1 = givenACryptoDevice() + val device2 = givenACryptoDevice() + val devices = listOf(device1, device2) + val fakeSession = fakeActiveSessionHolder.fakeSession + val flowSession = mockk() + every { fakeSession.flow() } returns flowSession + every { flowSession.liveUserCryptoDevices(any()) } returns flowOf(devices) + + fakeSession.fakeSharedSecretStorageService.givenIsRecoverySetupReturns(false) + + // When + val result = checkIfCurrentSessionCanBeVerifiedUseCase.execute() + + // Then + result shouldBeEqualTo true + verify { + flowSession.liveUserCryptoDevices(fakeSession.myUserId) + fakeSession.fakeSharedSecretStorageService.isRecoverySetup() + } + } + + @Test + fun `given recovery is setup when checking if session can be verified then result is true`() = runTest { + // Given + val device1 = givenACryptoDevice() + val devices = listOf(device1) + val fakeSession = fakeActiveSessionHolder.fakeSession + val flowSession = mockk() + every { fakeSession.flow() } returns flowSession + every { flowSession.liveUserCryptoDevices(any()) } returns flowOf(devices) + + fakeSession.fakeSharedSecretStorageService.givenIsRecoverySetupReturns(true) + + // When + val result = checkIfCurrentSessionCanBeVerifiedUseCase.execute() + + // Then + result shouldBeEqualTo true + verify { + flowSession.liveUserCryptoDevices(fakeSession.myUserId) + fakeSession.fakeSharedSecretStorageService.isRecoverySetup() + } + } + + @Test + fun `given recovery is not setup and there are no other sessions when checking if session can be verified then result is false`() = runTest { + // Given + val device1 = givenACryptoDevice() + val devices = listOf(device1) + val fakeSession = fakeActiveSessionHolder.fakeSession + val flowSession = mockk() + every { fakeSession.flow() } returns flowSession + every { flowSession.liveUserCryptoDevices(any()) } returns flowOf(devices) + + fakeSession.fakeSharedSecretStorageService.givenIsRecoverySetupReturns(false) + + // When + val result = checkIfCurrentSessionCanBeVerifiedUseCase.execute() + + // Then + result shouldBeEqualTo false + verify { + flowSession.liveUserCryptoDevices(fakeSession.myUserId) + fakeSession.fakeSharedSecretStorageService.isRecoverySetup() + } + } + + private fun givenACryptoDevice(): CryptoDeviceInfo = mockk() +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSharedSecretStorageService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSharedSecretStorageService.kt index 6ec9a4b593..1dc36de709 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeSharedSecretStorageService.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSharedSecretStorageService.kt @@ -16,6 +16,8 @@ package im.vector.app.test.fakes +import io.mockk.every +import io.mockk.mockk import org.matrix.android.sdk.api.listeners.ProgressListener import org.matrix.android.sdk.api.session.securestorage.IntegrityResult import org.matrix.android.sdk.api.session.securestorage.KeyInfoResult @@ -26,7 +28,7 @@ import org.matrix.android.sdk.api.session.securestorage.SharedSecretStorageServi import org.matrix.android.sdk.api.session.securestorage.SsssKeyCreationInfo import org.matrix.android.sdk.api.session.securestorage.SsssKeySpec -class FakeSharedSecretStorageService : SharedSecretStorageService { +class FakeSharedSecretStorageService : SharedSecretStorageService by mockk() { var integrityResult: IntegrityResult = IntegrityResult.Error(SharedSecretStorageError.OtherError(IllegalStateException())) var _defaultKey: KeyInfoResult = KeyInfoResult.Error(SharedSecretStorageError.OtherError(IllegalStateException())) @@ -76,4 +78,8 @@ class FakeSharedSecretStorageService : SharedSecretStorageService { override suspend fun requestSecret(name: String, myOtherDeviceId: String) { TODO("Not yet implemented") } + + fun givenIsRecoverySetupReturns(isRecoverySetup: Boolean) { + every { isRecoverySetup() } returns isRecoverySetup + } } From 35db958279e51ec2599bb84a7410995f00c5cd8c Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 14 Sep 2022 17:39:41 +0200 Subject: [PATCH 047/187] Adding unit tests for new action in DevicesViewModel --- .../settings/devices/v2/DevicesViewModel.kt | 1 - .../devices/v2/DevicesViewModelTest.kt | 48 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt index 44dc599765..5667b1cc57 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt @@ -101,7 +101,6 @@ class DevicesViewModel @AssistedInject constructor( } } - // TODO add unit tests private fun handleVerifyCurrentSessionAction() { viewModelScope.launch { val currentSessionCanBeVerified = checkIfCurrentSessionCanBeVerifiedUseCase.execute() diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt index d9a64c82ef..18796191af 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt @@ -145,6 +145,54 @@ class DevicesViewModelTest { coVerify { refreshDevicesOnCryptoDevicesChangeUseCase.execute() } } + @Test + fun `given current session can be verified when handling verify current session action then self verification event is posted`() { + // Given + givenVerificationService() + givenCurrentSessionCrossSigningInfo() + givenDeviceFullInfoList() + givenRefreshDevicesOnCryptoDevicesChange() + val verifyCurrentSessionAction = DevicesAction.VerifyCurrentSession + coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns true + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(verifyCurrentSessionAction) + + // Then + viewModelTest + .assertEvent { it is DevicesViewEvent.SelfVerification } + .finish() + coVerify { + checkIfCurrentSessionCanBeVerifiedUseCase.execute() + } + } + + @Test + fun `given current session cannot be verified when handling verify current session action then reset secrets event is posted`() { + // Given + givenVerificationService() + givenCurrentSessionCrossSigningInfo() + givenDeviceFullInfoList() + givenRefreshDevicesOnCryptoDevicesChange() + val verifyCurrentSessionAction = DevicesAction.VerifyCurrentSession + coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns false + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(verifyCurrentSessionAction) + + // Then + viewModelTest + .assertEvent { it is DevicesViewEvent.PromptResetSecrets } + .finish() + coVerify { + checkIfCurrentSessionCanBeVerifiedUseCase.execute() + } + } + private fun givenVerificationService(): FakeVerificationService { val fakeVerificationService = fakeActiveSessionHolder .fakeSession From 32b560649844636f6830e7c48abed34df0292891 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 15 Sep 2022 11:03:01 +0200 Subject: [PATCH 048/187] Fixing missing event to start verification process --- .../features/settings/devices/VectorSettingsDevicesFragment.kt | 3 +-- .../settings/devices/v2/VectorSettingsDevicesFragment.kt | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt index 5b19b7a8d2..135c684e76 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/VectorSettingsDevicesFragment.kt @@ -85,8 +85,7 @@ class VectorSettingsDevicesFragment : ).show(childFragmentManager, "REQPOP") } is DevicesViewEvents.SelfVerification -> { - VerificationBottomSheet.forSelfVerification(it.session) - .show(childFragmentManager, "REQPOP") + navigator.requestSelfSessionVerification(requireActivity()) } is DevicesViewEvents.ShowManuallyVerify -> { ManuallyVerifyDialog.show(requireActivity(), it.cryptoDeviceInfo) { diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt index 3713357b19..7cfa218bf0 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -101,8 +101,7 @@ class VectorSettingsDevicesFragment : ).show(childFragmentManager, "REQPOP") } is DevicesViewEvent.SelfVerification -> { - VerificationBottomSheet.forSelfVerification(it.session) - .show(childFragmentManager, "REQPOP") + navigator.requestSelfSessionVerification(requireActivity()) } is DevicesViewEvent.ShowManuallyVerify -> { ManuallyVerifyDialog.show(requireActivity(), it.cryptoDeviceInfo) { From fa990351afa08d7a845d90dc3c8db659cea9da91 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 15 Sep 2022 14:00:08 +0200 Subject: [PATCH 049/187] Editing changelog entry --- changelog.d/7114.wip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.d/7114.wip b/changelog.d/7114.wip index d5bd584feb..79ad705132 100644 --- a/changelog.d/7114.wip +++ b/changelog.d/7114.wip @@ -1 +1 @@ -[Device management] Verify a session +[Device management] Verify current session From 584c6994099b093da8ecaf8b7ae259d1d4ecb153 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 15 Sep 2022 14:42:22 +0200 Subject: [PATCH 050/187] Verify current session in Session overview screen --- .../devices/v2/IsCurrentSessionUseCase.kt | 30 +++++++ .../v2/overview/SessionOverviewAction.kt | 4 +- .../v2/overview/SessionOverviewFragment.kt | 21 ++++- .../v2/overview/SessionOverviewViewEvent.kt | 25 ++++++ .../v2/overview/SessionOverviewViewModel.kt | 43 ++++++++-- .../devices/v2/IsCurrentSessionUseCaseTest.kt | 82 +++++++++++++++++++ .../overview/SessionOverviewViewModelTest.kt | 77 +++++++++++++---- 7 files changed, 256 insertions(+), 26 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCase.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt create mode 100644 vector/src/test/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCaseTest.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCase.kt new file mode 100644 index 0000000000..885908120a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCase.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2 + +import im.vector.app.core.di.ActiveSessionHolder +import javax.inject.Inject + +class IsCurrentSessionUseCase @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, +) { + + fun execute(deviceId: String): Boolean { + val currentDeviceId = activeSessionHolder.getSafeActiveSession()?.sessionParams?.deviceId.orEmpty() + return deviceId.isNotEmpty() && deviceId == currentDeviceId + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt index c028c08ec4..0e923b4c9b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt @@ -18,4 +18,6 @@ package im.vector.app.features.settings.devices.v2.overview import im.vector.app.core.platform.VectorViewModelAction -sealed class SessionOverviewAction : VectorViewModelAction +sealed class SessionOverviewAction : VectorViewModelAction { + data class VerifySession(val deviceId: String) : SessionOverviewAction() +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index ed8ec1a55f..98f4eb823b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -34,6 +34,7 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.DrawableProvider import im.vector.app.databinding.FragmentSessionOverviewBinding +import im.vector.app.features.crypto.recover.SetupMode import im.vector.app.features.settings.devices.v2.DeviceFullInfo import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState import javax.inject.Inject @@ -62,6 +63,7 @@ class SessionOverviewFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) initSessionInfoView() + observeViewEvents() } private fun initSessionInfoView() { @@ -70,6 +72,19 @@ class SessionOverviewFragment : } } + private fun observeViewEvents() { + viewModel.observeViewEvents { + when (it) { + is SessionOverviewViewEvent.SelfVerification -> { + navigator.requestSelfSessionVerification(requireActivity()) + } + is SessionOverviewViewEvent.PromptResetSecrets -> { + navigator.open4SSetup(requireActivity(), SetupMode.PASSPHRASE_AND_NEEDED_SECRETS_RESET) + } + } + } + } + override fun onDestroyView() { cleanUpSessionInfoView() super.onDestroyView() @@ -81,7 +96,7 @@ class SessionOverviewFragment : override fun invalidate() = withState(viewModel) { state -> updateToolbar(state.isCurrentSession) - updateVerifyButton() + updateVerifyButton(state.deviceId) updateEntryDetails(state.deviceId) if (state.deviceInfo is Success) { renderSessionInfo(state.isCurrentSession, state.deviceInfo.invoke()) @@ -97,9 +112,9 @@ class SessionOverviewFragment : ?.setTitle(titleResId) } - private fun updateVerifyButton() { + private fun updateVerifyButton(deviceId: String) { views.sessionOverviewInfo.viewVerifyButton.debouncedClicks { - // TODO show bottom Sheet verification process + viewModel.handle(SessionOverviewAction.VerifySession(deviceId)) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt new file mode 100644 index 0000000000..3b1ee2609e --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.overview + +import im.vector.app.core.platform.VectorViewEvents +import org.matrix.android.sdk.api.session.Session + +sealed class SessionOverviewViewEvent : VectorViewEvents { + data class SelfVerification(val session: Session) : SessionOverviewViewEvent() + object PromptResetSecrets : SessionOverviewViewEvent() +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index bdcdc40c56..32c6aed541 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -21,19 +21,23 @@ import com.airbnb.mvrx.Success import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory -import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.settings.devices.v2.IsCurrentSessionUseCase +import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach -import org.matrix.android.sdk.api.session.Session +import kotlinx.coroutines.launch class SessionOverviewViewModel @AssistedInject constructor( @Assisted val initialState: SessionOverviewViewState, - session: Session, + private val activeSessionHolder: ActiveSessionHolder, + private val isCurrentSessionUseCase: IsCurrentSessionUseCase, private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase, -) : VectorViewModel(initialState) { + private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, +) : VectorViewModel(initialState) { companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() @@ -43,14 +47,16 @@ class SessionOverviewViewModel @AssistedInject constructor( } init { - val currentDeviceId = session.sessionParams.deviceId.orEmpty() setState { - copy(isCurrentSession = deviceId.isNotEmpty() && deviceId == currentDeviceId) + copy(isCurrentSession = isCurrentSession(deviceId)) } - observeSessionInfo(initialState.deviceId) } + private fun isCurrentSession(deviceId: String): Boolean { + return isCurrentSessionUseCase.execute(deviceId) + } + private fun observeSessionInfo(deviceId: String) { getDeviceFullInfoUseCase.execute(deviceId) .onEach { setState { copy(deviceInfo = Success(it)) } } @@ -58,6 +64,27 @@ class SessionOverviewViewModel @AssistedInject constructor( } override fun handle(action: SessionOverviewAction) { - TODO("Implement when adding the first action") + when (action) { + is SessionOverviewAction.VerifySession -> handleVerifySessionAction(action) + } + } + + private fun handleVerifySessionAction(verifySession: SessionOverviewAction.VerifySession) { + if (isCurrentSession(verifySession.deviceId)) { + handleVerifyCurrentSession() + } + } + + private fun handleVerifyCurrentSession() { + viewModelScope.launch { + val currentSessionCanBeVerified = checkIfCurrentSessionCanBeVerifiedUseCase.execute() + if (currentSessionCanBeVerified) { + activeSessionHolder.getSafeActiveSession()?.let { session -> + _viewEvents.post(SessionOverviewViewEvent.SelfVerification(session)) + } + } else { + _viewEvents.post(SessionOverviewViewEvent.PromptResetSecrets) + } + } } } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCaseTest.kt new file mode 100644 index 0000000000..25cd150b21 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCaseTest.kt @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2 + +import im.vector.app.test.fakes.FakeActiveSessionHolder +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.amshove.kluent.shouldBe +import org.junit.Test +import org.matrix.android.sdk.api.auth.data.SessionParams + +private const val A_SESSION_ID_1 = "session-id-1" +private const val A_SESSION_ID_2 = "session-id-2" + +class IsCurrentSessionUseCaseTest { + + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + + private val isCurrentSessionUseCase = IsCurrentSessionUseCase( + activeSessionHolder = fakeActiveSessionHolder.instance, + ) + + @Test + fun `given the session id of the current session when checking if id is current session then result is true`() { + // Given + val sessionParams = givenIdForCurrentSession(A_SESSION_ID_1) + + // When + val result = isCurrentSessionUseCase.execute(A_SESSION_ID_1) + + // Then + result shouldBe true + verify { sessionParams.deviceId } + } + + @Test + fun `given a session id different from the current session id when checking if id is current session then result is false`() { + // Given + val sessionParams = givenIdForCurrentSession(A_SESSION_ID_1) + + // When + val result = isCurrentSessionUseCase.execute(A_SESSION_ID_2) + + // Then + result shouldBe false + verify { sessionParams.deviceId } + } + + @Test + fun `given no current active session when checking if id is current session then result is false`() { + // Given + fakeActiveSessionHolder.givenGetSafeActiveSessionReturns(null) + + // When + val result = isCurrentSessionUseCase.execute(A_SESSION_ID_1) + + // Then + result shouldBe false + } + + private fun givenIdForCurrentSession(deviceId: String): SessionParams { + val sessionParams = mockk() + every { sessionParams.deviceId } returns deviceId + fakeActiveSessionHolder.fakeSession.givenSessionParams(sessionParams) + return sessionParams + } +} diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index 8d4e49ef85..1fb14f678b 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -19,16 +19,19 @@ package im.vector.app.features.settings.devices.v2.overview import com.airbnb.mvrx.Success import com.airbnb.mvrx.test.MvRxTestRule import im.vector.app.features.settings.devices.v2.DeviceFullInfo -import im.vector.app.test.fakes.FakeSession +import im.vector.app.features.settings.devices.v2.IsCurrentSessionUseCase +import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase +import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.test import im.vector.app.test.testDispatcher +import io.mockk.coEvery +import io.mockk.coVerify import io.mockk.every import io.mockk.mockk import io.mockk.verify import kotlinx.coroutines.flow.flowOf import org.junit.Rule import org.junit.Test -import org.matrix.android.sdk.api.auth.data.SessionParams private const val A_SESSION_ID = "session-id" @@ -40,24 +43,29 @@ class SessionOverviewViewModelTest { private val args = SessionOverviewArgs( deviceId = A_SESSION_ID ) - private val fakeSession = FakeSession() + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + private val isCurrentSessionUseCase = mockk() private val getDeviceFullInfoUseCase = mockk() + private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk() private fun createViewModel() = SessionOverviewViewModel( initialState = SessionOverviewViewState(args), - session = fakeSession, - getDeviceFullInfoUseCase = getDeviceFullInfoUseCase + activeSessionHolder = fakeActiveSessionHolder.instance, + isCurrentSessionUseCase = isCurrentSessionUseCase, + getDeviceFullInfoUseCase = getDeviceFullInfoUseCase, + checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase, ) @Test fun `given the viewModel has been initialized then viewState is updated with session info`() { // Given - val sessionParams = givenIdForSession(A_SESSION_ID) val deviceFullInfo = mockk() every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) + val isCurrentSession = true + every { isCurrentSessionUseCase.execute(any()) } returns isCurrentSession val expectedState = SessionOverviewViewState( deviceId = A_SESSION_ID, - isCurrentSession = true, + isCurrentSession = isCurrentSession, deviceInfo = Success(deviceFullInfo) ) @@ -68,14 +76,55 @@ class SessionOverviewViewModelTest { viewModel.test() .assertLatestState { state -> state == expectedState } .finish() - verify { sessionParams.deviceId } - verify { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } + verify { + isCurrentSessionUseCase.execute(A_SESSION_ID) + getDeviceFullInfoUseCase.execute(A_SESSION_ID) + } } - private fun givenIdForSession(deviceId: String): SessionParams { - val sessionParams = mockk() - every { sessionParams.deviceId } returns deviceId - fakeSession.givenSessionParams(sessionParams) - return sessionParams + @Test + fun `given current session can be verified when handling verify current session action then self verification event is posted`() { + // Given + val deviceFullInfo = mockk() + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) + every { isCurrentSessionUseCase.execute(any()) } returns true + val verifySessionAction = SessionOverviewAction.VerifySession(A_SESSION_ID) + coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns true + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(verifySessionAction) + + // Then + viewModelTest + .assertEvent { it is SessionOverviewViewEvent.SelfVerification } + .finish() + coVerify { + checkIfCurrentSessionCanBeVerifiedUseCase.execute() + } + } + + @Test + fun `given current session cannot be verified when handling verify current session action then reset secrets event is posted`() { + // Given + val deviceFullInfo = mockk() + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) + every { isCurrentSessionUseCase.execute(any()) } returns true + val verifySessionAction = SessionOverviewAction.VerifySession(A_SESSION_ID) + coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns false + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(verifySessionAction) + + // Then + viewModelTest + .assertEvent { it is SessionOverviewViewEvent.PromptResetSecrets } + .finish() + coVerify { + checkIfCurrentSessionCanBeVerifiedUseCase.execute() + } } } From e0c4706cf956a8056863b42a1c041ffa20c0da52 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 09:39:30 +0200 Subject: [PATCH 051/187] Removing non necessary session arg from ViewEvent --- .../app/features/settings/devices/v2/DevicesViewEvent.kt | 3 +-- .../app/features/settings/devices/v2/DevicesViewModel.kt | 4 +--- .../devices/v2/overview/SessionOverviewViewEvent.kt | 3 +-- .../devices/v2/overview/SessionOverviewViewModel.kt | 6 +----- .../devices/v2/overview/SessionOverviewViewModelTest.kt | 3 --- 5 files changed, 4 insertions(+), 15 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewEvent.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewEvent.kt index e83004843d..c78c20f792 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewEvent.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewEvent.kt @@ -18,7 +18,6 @@ package im.vector.app.features.settings.devices.v2 import im.vector.app.core.platform.VectorViewEvents import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse -import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo @@ -28,7 +27,7 @@ sealed class DevicesViewEvent : VectorViewEvents { data class RequestReAuth(val registrationFlowResponse: RegistrationFlowResponse, val lastErrorCode: String?) : DevicesViewEvent() data class PromptRenameDevice(val deviceInfo: DeviceInfo) : DevicesViewEvent() data class ShowVerifyDevice(val userId: String, val transactionId: String?) : DevicesViewEvent() - data class SelfVerification(val session: Session) : DevicesViewEvent() + object SelfVerification : DevicesViewEvent() data class ShowManuallyVerify(val cryptoDeviceInfo: CryptoDeviceInfo) : DevicesViewEvent() object PromptResetSecrets : DevicesViewEvent() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt index 5667b1cc57..730400bfcf 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt @@ -105,9 +105,7 @@ class DevicesViewModel @AssistedInject constructor( viewModelScope.launch { val currentSessionCanBeVerified = checkIfCurrentSessionCanBeVerifiedUseCase.execute() if (currentSessionCanBeVerified) { - activeSessionHolder.getSafeActiveSession()?.let { session -> - _viewEvents.post(DevicesViewEvent.SelfVerification(session)) - } + _viewEvents.post(DevicesViewEvent.SelfVerification) } else { _viewEvents.post(DevicesViewEvent.PromptResetSecrets) } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt index 3b1ee2609e..83d438ecb4 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt @@ -17,9 +17,8 @@ package im.vector.app.features.settings.devices.v2.overview import im.vector.app.core.platform.VectorViewEvents -import org.matrix.android.sdk.api.session.Session sealed class SessionOverviewViewEvent : VectorViewEvents { - data class SelfVerification(val session: Session) : SessionOverviewViewEvent() + object SelfVerification : SessionOverviewViewEvent() object PromptResetSecrets : SessionOverviewViewEvent() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index 32c6aed541..5b51483afe 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -21,7 +21,6 @@ import com.airbnb.mvrx.Success import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject -import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel @@ -33,7 +32,6 @@ import kotlinx.coroutines.launch class SessionOverviewViewModel @AssistedInject constructor( @Assisted val initialState: SessionOverviewViewState, - private val activeSessionHolder: ActiveSessionHolder, private val isCurrentSessionUseCase: IsCurrentSessionUseCase, private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase, private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, @@ -79,9 +77,7 @@ class SessionOverviewViewModel @AssistedInject constructor( viewModelScope.launch { val currentSessionCanBeVerified = checkIfCurrentSessionCanBeVerifiedUseCase.execute() if (currentSessionCanBeVerified) { - activeSessionHolder.getSafeActiveSession()?.let { session -> - _viewEvents.post(SessionOverviewViewEvent.SelfVerification(session)) - } + _viewEvents.post(SessionOverviewViewEvent.SelfVerification) } else { _viewEvents.post(SessionOverviewViewEvent.PromptResetSecrets) } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index 1fb14f678b..f25c25bb8e 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -21,7 +21,6 @@ import com.airbnb.mvrx.test.MvRxTestRule import im.vector.app.features.settings.devices.v2.DeviceFullInfo import im.vector.app.features.settings.devices.v2.IsCurrentSessionUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase -import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.test import im.vector.app.test.testDispatcher import io.mockk.coEvery @@ -43,14 +42,12 @@ class SessionOverviewViewModelTest { private val args = SessionOverviewArgs( deviceId = A_SESSION_ID ) - private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val isCurrentSessionUseCase = mockk() private val getDeviceFullInfoUseCase = mockk() private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk() private fun createViewModel() = SessionOverviewViewModel( initialState = SessionOverviewViewState(args), - activeSessionHolder = fakeActiveSessionHolder.instance, isCurrentSessionUseCase = isCurrentSessionUseCase, getDeviceFullInfoUseCase = getDeviceFullInfoUseCase, checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase, From cf6b8d76a822623d7eed51338fddb3b25b4b97ff Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 09:44:46 +0200 Subject: [PATCH 052/187] Removing non necessary session id arg from ViewAction --- .../devices/v2/overview/SessionOverviewAction.kt | 2 +- .../v2/overview/SessionOverviewFragment.kt | 16 ++++++++-------- .../v2/overview/SessionOverviewViewModel.kt | 6 +++--- .../v2/overview/SessionOverviewViewModelTest.kt | 4 ++-- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt index 0e923b4c9b..1118c5dc5b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewAction.kt @@ -19,5 +19,5 @@ package im.vector.app.features.settings.devices.v2.overview import im.vector.app.core.platform.VectorViewModelAction sealed class SessionOverviewAction : VectorViewModelAction { - data class VerifySession(val deviceId: String) : SessionOverviewAction() + object VerifySession : SessionOverviewAction() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index 98f4eb823b..4c83408fe7 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -62,8 +62,9 @@ class SessionOverviewFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - initSessionInfoView() observeViewEvents() + initSessionInfoView() + initVerifyButton() } private fun initSessionInfoView() { @@ -72,6 +73,12 @@ class SessionOverviewFragment : } } + private fun initVerifyButton() { + views.sessionOverviewInfo.viewVerifyButton.debouncedClicks { + viewModel.handle(SessionOverviewAction.VerifySession) + } + } + private fun observeViewEvents() { viewModel.observeViewEvents { when (it) { @@ -96,7 +103,6 @@ class SessionOverviewFragment : override fun invalidate() = withState(viewModel) { state -> updateToolbar(state.isCurrentSession) - updateVerifyButton(state.deviceId) updateEntryDetails(state.deviceId) if (state.deviceInfo is Success) { renderSessionInfo(state.isCurrentSession, state.deviceInfo.invoke()) @@ -112,12 +118,6 @@ class SessionOverviewFragment : ?.setTitle(titleResId) } - private fun updateVerifyButton(deviceId: String) { - views.sessionOverviewInfo.viewVerifyButton.debouncedClicks { - viewModel.handle(SessionOverviewAction.VerifySession(deviceId)) - } - } - private fun updateEntryDetails(deviceId: String) { views.sessionOverviewEntryDetails.setOnClickListener { viewNavigator.navigateToSessionDetails(requireContext(), deviceId) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index 5b51483afe..bcf7542783 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -63,12 +63,12 @@ class SessionOverviewViewModel @AssistedInject constructor( override fun handle(action: SessionOverviewAction) { when (action) { - is SessionOverviewAction.VerifySession -> handleVerifySessionAction(action) + is SessionOverviewAction.VerifySession -> handleVerifySessionAction() } } - private fun handleVerifySessionAction(verifySession: SessionOverviewAction.VerifySession) { - if (isCurrentSession(verifySession.deviceId)) { + private fun handleVerifySessionAction() = withState { viewState -> + if (isCurrentSession(viewState.deviceId)) { handleVerifyCurrentSession() } } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index f25c25bb8e..71978129d3 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -85,7 +85,7 @@ class SessionOverviewViewModelTest { val deviceFullInfo = mockk() every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) every { isCurrentSessionUseCase.execute(any()) } returns true - val verifySessionAction = SessionOverviewAction.VerifySession(A_SESSION_ID) + val verifySessionAction = SessionOverviewAction.VerifySession coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns true // When @@ -108,7 +108,7 @@ class SessionOverviewViewModelTest { val deviceFullInfo = mockk() every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) every { isCurrentSessionUseCase.execute(any()) } returns true - val verifySessionAction = SessionOverviewAction.VerifySession(A_SESSION_ID) + val verifySessionAction = SessionOverviewAction.VerifySession coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns false // When From 54a4dc7e9a794fc9f85ef61a8d027e0ca044d7c3 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 14:46:24 +0200 Subject: [PATCH 053/187] Inverting some arguments to ease readability --- .../vector/app/features/settings/devices/v2/DevicesViewModel.kt | 2 +- .../app/features/settings/devices/v2/DevicesViewModelTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt index 730400bfcf..96d169bf02 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt @@ -37,8 +37,8 @@ class DevicesViewModel @AssistedInject constructor( private val getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase, private val getDeviceFullInfoListUseCase: GetDeviceFullInfoListUseCase, private val refreshDevicesOnCryptoDevicesChangeUseCase: RefreshDevicesOnCryptoDevicesChangeUseCase, - refreshDevicesUseCase: RefreshDevicesUseCase, private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, + refreshDevicesUseCase: RefreshDevicesUseCase, ) : VectorSessionsListViewModel(initialState, activeSessionHolder, refreshDevicesUseCase) { @AssistedFactory diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt index 18796191af..0e04c2ab51 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt @@ -55,8 +55,8 @@ class DevicesViewModelTest { getCurrentSessionCrossSigningInfoUseCase, getDeviceFullInfoListUseCase, refreshDevicesOnCryptoDevicesChangeUseCase, - refreshDevicesUseCase, checkIfCurrentSessionCanBeVerifiedUseCase, + refreshDevicesUseCase, ) } From c16e1ca2916973486f1d787f06cc1fa8630f52ca Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 15 Sep 2022 16:37:05 +0200 Subject: [PATCH 054/187] Adding changelog entry --- changelog.d/7143.wip | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7143.wip diff --git a/changelog.d/7143.wip b/changelog.d/7143.wip new file mode 100644 index 0000000000..588f7fb255 --- /dev/null +++ b/changelog.d/7143.wip @@ -0,0 +1 @@ +[Device management] Verify another session From a6cb25d0c3bfd18d659dca93f87196dbae3631a7 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Fri, 16 Sep 2022 10:10:54 +0200 Subject: [PATCH 055/187] Verification of another session --- .../devices/v2/list/SessionInfoView.kt | 8 ++++--- .../devices/v2/list/SessionInfoViewState.kt | 1 + .../v2/overview/SessionOverviewFragment.kt | 14 ++++++++++--- .../v2/overview/SessionOverviewViewEvent.kt | 3 ++- .../v2/overview/SessionOverviewViewModel.kt | 9 +++++++- .../v2/overview/SessionOverviewViewState.kt | 1 + .../overview/SessionOverviewViewModelTest.kt | 21 ++++++++++++++++++- 7 files changed, 48 insertions(+), 9 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt index 38bc0cb5d8..340a4f3c3a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoView.kt @@ -62,6 +62,7 @@ class SessionInfoView @JvmOverloads constructor( sessionInfoViewState.deviceFullInfo.roomEncryptionTrustLevel, sessionInfoViewState.isCurrentSession, sessionInfoViewState.isLearnMoreLinkVisible, + sessionInfoViewState.isVerifyButtonVisible, ) renderDeviceLastSeenDetails( sessionInfoViewState.deviceFullInfo.isInactive, @@ -78,12 +79,13 @@ class SessionInfoView @JvmOverloads constructor( encryptionTrustLevel: RoomEncryptionTrustLevel, isCurrentSession: Boolean, hasLearnMoreLink: Boolean, + isVerifyButtonVisible: Boolean, ) { views.sessionInfoVerificationStatusImageView.render(encryptionTrustLevel) if (encryptionTrustLevel == RoomEncryptionTrustLevel.Trusted) { renderCrossSigningVerified(isCurrentSession) } else { - renderCrossSigningUnverified(isCurrentSession) + renderCrossSigningUnverified(isCurrentSession, isVerifyButtonVisible) } if (hasLearnMoreLink) { appendLearnMoreToVerificationStatus() @@ -120,7 +122,7 @@ class SessionInfoView @JvmOverloads constructor( views.sessionInfoVerifySessionButton.isVisible = false } - private fun renderCrossSigningUnverified(isCurrentSession: Boolean) { + private fun renderCrossSigningUnverified(isCurrentSession: Boolean, isVerifyButtonVisible: Boolean) { views.sessionInfoVerificationStatusTextView.text = context.getString(R.string.device_manager_verification_status_unverified) views.sessionInfoVerificationStatusTextView.setTextColor(ThemeUtils.getColor(context, R.attr.colorError)) val statusResId = if (isCurrentSession) { @@ -129,7 +131,7 @@ class SessionInfoView @JvmOverloads constructor( R.string.device_manager_verification_status_detail_other_session_unverified } views.sessionInfoVerificationStatusDetailTextView.text = context.getString(statusResId) - views.sessionInfoVerifySessionButton.isVisible = true + views.sessionInfoVerifySessionButton.isVisible = isVerifyButtonVisible } // TODO. We don't have this info yet. Update later accordingly. diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoViewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoViewState.kt index 60e1234820..287bb956f5 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SessionInfoViewState.kt @@ -21,6 +21,7 @@ import im.vector.app.features.settings.devices.v2.DeviceFullInfo data class SessionInfoViewState( val isCurrentSession: Boolean, val deviceFullInfo: DeviceFullInfo, + val isVerifyButtonVisible: Boolean = true, val isDetailsButtonVisible: Boolean = true, val isLearnMoreLinkVisible: Boolean = false, val isLastSeenDetailsVisible: Boolean = false, diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index 4c83408fe7..db293e88a9 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -82,9 +82,12 @@ class SessionOverviewFragment : private fun observeViewEvents() { viewModel.observeViewEvents { when (it) { - is SessionOverviewViewEvent.SelfVerification -> { + is SessionOverviewViewEvent.ShowVerifyCurrentSession -> { navigator.requestSelfSessionVerification(requireActivity()) } + is SessionOverviewViewEvent.ShowVerifyOtherSession -> { + navigator.requestSessionVerification(requireActivity(), it.deviceId) + } is SessionOverviewViewEvent.PromptResetSecrets -> { navigator.open4SSetup(requireActivity(), SetupMode.PASSPHRASE_AND_NEEDED_SECRETS_RESET) } @@ -105,7 +108,7 @@ class SessionOverviewFragment : updateToolbar(state.isCurrentSession) updateEntryDetails(state.deviceId) if (state.deviceInfo is Success) { - renderSessionInfo(state.isCurrentSession, state.deviceInfo.invoke()) + renderSessionInfo(state.isCurrentSession, state.deviceInfo.invoke(), state.isCurrentSessionTrusted) } else { hideSessionInfo() } @@ -124,11 +127,16 @@ class SessionOverviewFragment : } } - private fun renderSessionInfo(isCurrentSession: Boolean, deviceFullInfo: DeviceFullInfo) { + private fun renderSessionInfo( + isCurrentSession: Boolean, + deviceFullInfo: DeviceFullInfo, + isCurrentSessionTrusted: Boolean, + ) { views.sessionOverviewInfo.isVisible = true val viewState = SessionInfoViewState( isCurrentSession = isCurrentSession, deviceFullInfo = deviceFullInfo, + isVerifyButtonVisible = isCurrentSession || isCurrentSessionTrusted, isDetailsButtonVisible = false, isLearnMoreLinkVisible = true, isLastSeenDetailsVisible = true, diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt index 83d438ecb4..8508b395ad 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewEvent.kt @@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices.v2.overview import im.vector.app.core.platform.VectorViewEvents sealed class SessionOverviewViewEvent : VectorViewEvents { - object SelfVerification : SessionOverviewViewEvent() + object ShowVerifyCurrentSession : SessionOverviewViewEvent() + data class ShowVerifyOtherSession(val deviceId: String) : SessionOverviewViewEvent() object PromptResetSecrets : SessionOverviewViewEvent() } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index bcf7542783..183469936f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -45,6 +45,7 @@ class SessionOverviewViewModel @AssistedInject constructor( } init { + // TODO check if current session is trusted setState { copy(isCurrentSession = isCurrentSession(deviceId)) } @@ -70,6 +71,8 @@ class SessionOverviewViewModel @AssistedInject constructor( private fun handleVerifySessionAction() = withState { viewState -> if (isCurrentSession(viewState.deviceId)) { handleVerifyCurrentSession() + } else { + handleVerifyOtherSession(verifySession.deviceId) } } @@ -77,10 +80,14 @@ class SessionOverviewViewModel @AssistedInject constructor( viewModelScope.launch { val currentSessionCanBeVerified = checkIfCurrentSessionCanBeVerifiedUseCase.execute() if (currentSessionCanBeVerified) { - _viewEvents.post(SessionOverviewViewEvent.SelfVerification) + _viewEvents.post(SessionOverviewViewEvent.ShowVerifyCurrentSession) } else { _viewEvents.post(SessionOverviewViewEvent.PromptResetSecrets) } } } + + private fun handleVerifyOtherSession(deviceId: String) { + _viewEvents.post(SessionOverviewViewEvent.ShowVerifyOtherSession(deviceId)) + } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt index a447336c23..1cb455dd5c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewState.kt @@ -24,6 +24,7 @@ import im.vector.app.features.settings.devices.v2.DeviceFullInfo data class SessionOverviewViewState( val deviceId: String, val isCurrentSession: Boolean = false, + val isCurrentSessionTrusted: Boolean = false, val deviceInfo: Async = Uninitialized, ) : MavericksState { constructor(args: SessionOverviewArgs) : this( diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index 71978129d3..ed7fc766c7 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -95,7 +95,7 @@ class SessionOverviewViewModelTest { // Then viewModelTest - .assertEvent { it is SessionOverviewViewEvent.SelfVerification } + .assertEvent { it is SessionOverviewViewEvent.ShowVerifyCurrentSession } .finish() coVerify { checkIfCurrentSessionCanBeVerifiedUseCase.execute() @@ -124,4 +124,23 @@ class SessionOverviewViewModelTest { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } } + + @Test + fun `given another session when handling verify session action then verify session event is posted`() { + // Given + val deviceFullInfo = mockk() + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) + every { isCurrentSessionUseCase.execute(any()) } returns false + val verifySessionAction = SessionOverviewAction.VerifySession(A_SESSION_ID) + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(verifySessionAction) + + // Then + viewModelTest + .assertEvent { it is SessionOverviewViewEvent.ShowVerifyOtherSession } + .finish() + } } From 95d133e0e2edbf497060992f69a70ba338d12ebd Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Fri, 16 Sep 2022 14:12:38 +0200 Subject: [PATCH 056/187] Moving some components inside the verification package --- .../app/features/settings/devices/DevicesViewModel.kt | 2 +- .../devices/GetCurrentSessionCrossSigningInfoUseCase.kt | 2 +- .../app/features/settings/devices/v2/DevicesViewModel.kt | 1 + .../app/features/settings/devices/v2/DevicesViewState.kt | 1 + .../settings/devices/v2/GetDeviceFullInfoListUseCase.kt | 3 +++ .../devices/v2/overview/GetDeviceFullInfoUseCase.kt | 4 ++-- .../devices/v2/overview/SessionOverviewViewModel.kt | 1 - .../v2/{ => verification}/CurrentSessionCrossSigningInfo.kt | 2 +- .../GetCurrentSessionCrossSigningInfoUseCase.kt | 2 +- .../GetEncryptionTrustLevelForCurrentDeviceUseCase.kt | 2 +- .../GetEncryptionTrustLevelForDeviceUseCase.kt | 2 +- .../GetEncryptionTrustLevelForOtherDeviceUseCase.kt | 2 +- .../devices/GetCurrentSessionCrossSigningInfoUseCaseTest.kt | 2 +- .../features/settings/devices/v2/DevicesViewModelTest.kt | 2 ++ .../settings/devices/v2/GetDeviceFullInfoListUseCaseTest.kt | 3 +++ .../devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt | 6 +++--- .../GetCurrentSessionCrossSigningInfoUseCaseTest.kt | 2 +- .../GetEncryptionTrustLevelForCurrentDeviceUseCaseTest.kt | 2 +- .../GetEncryptionTrustLevelForDeviceUseCaseTest.kt | 2 +- .../GetEncryptionTrustLevelForOtherDeviceUseCaseTest.kt | 2 +- 20 files changed, 27 insertions(+), 18 deletions(-) rename vector/src/main/java/im/vector/app/features/settings/devices/v2/{ => verification}/CurrentSessionCrossSigningInfo.kt (93%) rename vector/src/main/java/im/vector/app/features/settings/devices/v2/{ => verification}/GetCurrentSessionCrossSigningInfoUseCase.kt (96%) rename vector/src/main/java/im/vector/app/features/settings/devices/v2/{ => verification}/GetEncryptionTrustLevelForCurrentDeviceUseCase.kt (95%) rename vector/src/main/java/im/vector/app/features/settings/devices/v2/{ => verification}/GetEncryptionTrustLevelForDeviceUseCase.kt (96%) rename vector/src/main/java/im/vector/app/features/settings/devices/v2/{ => verification}/GetEncryptionTrustLevelForOtherDeviceUseCase.kt (96%) rename vector/src/test/java/im/vector/app/features/settings/devices/v2/{ => verification}/GetCurrentSessionCrossSigningInfoUseCaseTest.kt (98%) rename vector/src/test/java/im/vector/app/features/settings/devices/v2/{ => verification}/GetEncryptionTrustLevelForCurrentDeviceUseCaseTest.kt (96%) rename vector/src/test/java/im/vector/app/features/settings/devices/v2/{ => verification}/GetEncryptionTrustLevelForDeviceUseCaseTest.kt (98%) rename vector/src/test/java/im/vector/app/features/settings/devices/v2/{ => verification}/GetEncryptionTrustLevelForOtherDeviceUseCaseTest.kt (98%) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt index 30e7727860..95b852b809 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt @@ -34,7 +34,7 @@ import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.PublishDataSource import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.login.ReAuthHelper -import im.vector.app.features.settings.devices.v2.GetEncryptionTrustLevelForDeviceUseCase +import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase import im.vector.lib.core.utils.flow.throttleFirst import kotlinx.coroutines.Dispatchers diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCase.kt index 8b58bd0536..a27c30379b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCase.kt @@ -17,7 +17,7 @@ package im.vector.app.features.settings.devices import im.vector.app.core.di.ActiveSessionHolder -import im.vector.app.features.settings.devices.v2.CurrentSessionCrossSigningInfo +import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo import javax.inject.Inject class GetCurrentSessionCrossSigningInfoUseCase @Inject constructor( diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt index 96d169bf02..f1fe582e44 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewModel.kt @@ -26,6 +26,7 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase +import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewState.kt index 3fc061daa4..e8bed35e24 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/DevicesViewState.kt @@ -19,6 +19,7 @@ package im.vector.app.features.settings.devices.v2 import com.airbnb.mvrx.Async import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized +import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo data class DevicesViewState( val currentSessionCrossSigningInfo: CurrentSessionCrossSigningInfo = CurrentSessionCrossSigningInfo(), diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCase.kt index 3c0d3a5e56..ae38ba3d3f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCase.kt @@ -20,6 +20,9 @@ import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.filter.FilterDevicesUseCase import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase +import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo +import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase +import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.distinctUntilChanged diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt index 5a8106f2fd..bb2c4f4c6a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt @@ -19,8 +19,8 @@ package im.vector.app.features.settings.devices.v2.overview import androidx.lifecycle.asFlow import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.features.settings.devices.v2.DeviceFullInfo -import im.vector.app.features.settings.devices.v2.GetCurrentSessionCrossSigningInfoUseCase -import im.vector.app.features.settings.devices.v2.GetEncryptionTrustLevelForDeviceUseCase +import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase +import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index 183469936f..335341ab07 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -45,7 +45,6 @@ class SessionOverviewViewModel @AssistedInject constructor( } init { - // TODO check if current session is trusted setState { copy(isCurrentSession = isCurrentSession(deviceId)) } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/CurrentSessionCrossSigningInfo.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CurrentSessionCrossSigningInfo.kt similarity index 93% rename from vector/src/main/java/im/vector/app/features/settings/devices/v2/CurrentSessionCrossSigningInfo.kt rename to vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CurrentSessionCrossSigningInfo.kt index cccdb23d52..1dfab06b1d 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/CurrentSessionCrossSigningInfo.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/CurrentSessionCrossSigningInfo.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.features.settings.devices.v2 +package im.vector.app.features.settings.devices.v2.verification /** * Used to hold some info about the cross signing of the current Session. diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetCurrentSessionCrossSigningInfoUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCase.kt similarity index 96% rename from vector/src/main/java/im/vector/app/features/settings/devices/v2/GetCurrentSessionCrossSigningInfoUseCase.kt rename to vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCase.kt index cc848342de..182e493213 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetCurrentSessionCrossSigningInfoUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCase.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.features.settings.devices.v2 +package im.vector.app.features.settings.devices.v2.verification import im.vector.app.core.di.ActiveSessionHolder import kotlinx.coroutines.flow.Flow diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForCurrentDeviceUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForCurrentDeviceUseCase.kt similarity index 95% rename from vector/src/main/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForCurrentDeviceUseCase.kt rename to vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForCurrentDeviceUseCase.kt index 7e56d35570..2243471a23 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForCurrentDeviceUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForCurrentDeviceUseCase.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.features.settings.devices.v2 +package im.vector.app.features.settings.devices.v2.verification import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel import javax.inject.Inject diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForDeviceUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCase.kt similarity index 96% rename from vector/src/main/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForDeviceUseCase.kt rename to vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCase.kt index 6f0dcbface..ba9a380ade 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForDeviceUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCase.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.features.settings.devices.v2 +package im.vector.app.features.settings.devices.v2.verification import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForOtherDeviceUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForOtherDeviceUseCase.kt similarity index 96% rename from vector/src/main/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForOtherDeviceUseCase.kt rename to vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForOtherDeviceUseCase.kt index 7541b9b1d5..e674ccd8c5 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForOtherDeviceUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForOtherDeviceUseCase.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.features.settings.devices.v2 +package im.vector.app.features.settings.devices.v2.verification import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCaseTest.kt index 1a805f4c3e..e71a11710b 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCaseTest.kt @@ -16,7 +16,7 @@ package im.vector.app.features.settings.devices -import im.vector.app.features.settings.devices.v2.CurrentSessionCrossSigningInfo +import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo import im.vector.app.test.fakes.FakeActiveSessionHolder import io.mockk.every import io.mockk.mockk diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt index 0e04c2ab51..f4160da9fd 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt @@ -19,6 +19,8 @@ package im.vector.app.features.settings.devices.v2 import com.airbnb.mvrx.Success import com.airbnb.mvrx.test.MvRxTestRule import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase +import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo +import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeVerificationService import im.vector.app.test.test diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCaseTest.kt index 54b160f196..c9dd9ddea6 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetDeviceFullInfoListUseCaseTest.kt @@ -19,6 +19,9 @@ package im.vector.app.features.settings.devices.v2 import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import im.vector.app.features.settings.devices.v2.filter.FilterDevicesUseCase import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase +import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo +import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase +import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.test import im.vector.app.test.testDispatcher diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt index 9c7515f2da..33a83cd590 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt @@ -18,10 +18,10 @@ package im.vector.app.features.settings.devices.v2.overview import androidx.lifecycle.MutableLiveData import androidx.lifecycle.asFlow -import im.vector.app.features.settings.devices.v2.CurrentSessionCrossSigningInfo +import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo import im.vector.app.features.settings.devices.v2.DeviceFullInfo -import im.vector.app.features.settings.devices.v2.GetCurrentSessionCrossSigningInfoUseCase -import im.vector.app.features.settings.devices.v2.GetEncryptionTrustLevelForDeviceUseCase +import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase +import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeFlowLiveDataConversions diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetCurrentSessionCrossSigningInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCaseTest.kt similarity index 98% rename from vector/src/test/java/im/vector/app/features/settings/devices/v2/GetCurrentSessionCrossSigningInfoUseCaseTest.kt rename to vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCaseTest.kt index f8ee1231ae..25d5766774 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetCurrentSessionCrossSigningInfoUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCaseTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.features.settings.devices.v2 +package im.vector.app.features.settings.devices.v2.verification import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeSession diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForCurrentDeviceUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForCurrentDeviceUseCaseTest.kt similarity index 96% rename from vector/src/test/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForCurrentDeviceUseCaseTest.kt rename to vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForCurrentDeviceUseCaseTest.kt index b2ce89df33..3f82cb0dd2 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForCurrentDeviceUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForCurrentDeviceUseCaseTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.features.settings.devices.v2 +package im.vector.app.features.settings.devices.v2.verification import org.amshove.kluent.shouldBeEqualTo import org.junit.Test diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForDeviceUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCaseTest.kt similarity index 98% rename from vector/src/test/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForDeviceUseCaseTest.kt rename to vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCaseTest.kt index e43fd49ffc..1b39fe5f73 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForDeviceUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForDeviceUseCaseTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.features.settings.devices.v2 +package im.vector.app.features.settings.devices.v2.verification import io.mockk.every import io.mockk.mockk diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForOtherDeviceUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForOtherDeviceUseCaseTest.kt similarity index 98% rename from vector/src/test/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForOtherDeviceUseCaseTest.kt rename to vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForOtherDeviceUseCaseTest.kt index 2aeffbbb0d..18f998cf97 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/GetEncryptionTrustLevelForOtherDeviceUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetEncryptionTrustLevelForOtherDeviceUseCaseTest.kt @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.features.settings.devices.v2 +package im.vector.app.features.settings.devices.v2.verification import org.amshove.kluent.shouldBeEqualTo import org.junit.Test From 921533e4b291b11a8b2a45c3db285ddebc3a9240 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Fri, 16 Sep 2022 15:03:14 +0200 Subject: [PATCH 057/187] Getting the current session verification status to change verify button visibility --- .../v2/overview/SessionOverviewViewModel.kt | 17 +++++++++ ...rrentSessionCrossSigningInfoUseCaseTest.kt | 7 +--- .../devices/v2/IsCurrentSessionUseCaseTest.kt | 9 +---- .../overview/SessionOverviewViewModelTest.kt | 38 +++++++++++++------ ...rrentSessionCrossSigningInfoUseCaseTest.kt | 5 +-- .../im/vector/app/test/fakes/FakeSession.kt | 7 ++++ 6 files changed, 54 insertions(+), 29 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index 335341ab07..40a78a4fd3 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -26,9 +26,12 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.settings.devices.v2.IsCurrentSessionUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel class SessionOverviewViewModel @AssistedInject constructor( @Assisted val initialState: SessionOverviewViewState, @@ -49,6 +52,7 @@ class SessionOverviewViewModel @AssistedInject constructor( copy(isCurrentSession = isCurrentSession(deviceId)) } observeSessionInfo(initialState.deviceId) + observeCurrentSessionInfo() } private fun isCurrentSession(deviceId: String): Boolean { @@ -61,6 +65,19 @@ class SessionOverviewViewModel @AssistedInject constructor( .launchIn(viewModelScope) } + private fun observeCurrentSessionInfo() { + activeSessionHolder.getSafeActiveSession() + ?.sessionParams + ?.deviceId + ?.let { deviceId -> + getDeviceFullInfoUseCase.execute(deviceId) + .map { it.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Trusted } + .distinctUntilChanged() + .onEach { setState { copy(isCurrentSessionTrusted = it) } } + .launchIn(viewModelScope) + } + } + override fun handle(action: SessionOverviewAction) { when (action) { is SessionOverviewAction.VerifySession -> handleVerifySessionAction() diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCaseTest.kt index e71a11710b..b9ba1b1c0b 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/GetCurrentSessionCrossSigningInfoUseCaseTest.kt @@ -18,11 +18,8 @@ package im.vector.app.features.settings.devices import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo import im.vector.app.test.fakes.FakeActiveSessionHolder -import io.mockk.every -import io.mockk.mockk import org.amshove.kluent.shouldBeEqualTo import org.junit.Test -import org.matrix.android.sdk.api.auth.data.SessionParams private const val A_DEVICE_ID = "device-id" @@ -36,9 +33,7 @@ class GetCurrentSessionCrossSigningInfoUseCaseTest { @Test fun `given the active session when getting cross signing info then the result is correct`() { - val sessionParams = mockk() - every { sessionParams.deviceId } returns A_DEVICE_ID - fakeActiveSessionHolder.fakeSession.givenSessionParams(sessionParams) + fakeActiveSessionHolder.fakeSession.givenSessionId(A_DEVICE_ID) val isCrossSigningInitialized = true fakeActiveSessionHolder.fakeSession .fakeCryptoService diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCaseTest.kt index 25cd150b21..09a94ac08b 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/IsCurrentSessionUseCaseTest.kt @@ -17,8 +17,6 @@ package im.vector.app.features.settings.devices.v2 import im.vector.app.test.fakes.FakeActiveSessionHolder -import io.mockk.every -import io.mockk.mockk import io.mockk.verify import org.amshove.kluent.shouldBe import org.junit.Test @@ -73,10 +71,7 @@ class IsCurrentSessionUseCaseTest { result shouldBe false } - private fun givenIdForCurrentSession(deviceId: String): SessionParams { - val sessionParams = mockk() - every { sessionParams.deviceId } returns deviceId - fakeActiveSessionHolder.fakeSession.givenSessionParams(sessionParams) - return sessionParams + private fun givenIdForCurrentSession(sessionId: String): SessionParams { + return fakeActiveSessionHolder.fakeSession.givenSessionId(sessionId) } } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index ed7fc766c7..3ba3e616df 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -31,8 +31,10 @@ import io.mockk.verify import kotlinx.coroutines.flow.flowOf import org.junit.Rule import org.junit.Test +import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel -private const val A_SESSION_ID = "session-id" +private const val A_SESSION_ID_1 = "session-id-1" +private const val A_SESSION_ID_2 = "session-id-2" class SessionOverviewViewModelTest { @@ -40,7 +42,7 @@ class SessionOverviewViewModelTest { val mvRxTestRule = MvRxTestRule(testDispatcher = testDispatcher) private val args = SessionOverviewArgs( - deviceId = A_SESSION_ID + deviceId = A_SESSION_ID_1 ) private val isCurrentSessionUseCase = mockk() private val getDeviceFullInfoUseCase = mockk() @@ -54,16 +56,18 @@ class SessionOverviewViewModelTest { ) @Test - fun `given the viewModel has been initialized then viewState is updated with session info`() { + fun `given the viewModel has been initialized then viewState is updated with session info and current session verification status`() { // Given val deviceFullInfo = mockk() - every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) val isCurrentSession = true every { isCurrentSessionUseCase.execute(any()) } returns isCurrentSession + givenCurrentSessionIsTrusted() val expectedState = SessionOverviewViewState( - deviceId = A_SESSION_ID, + deviceId = A_SESSION_ID_1, isCurrentSession = isCurrentSession, - deviceInfo = Success(deviceFullInfo) + deviceInfo = Success(deviceFullInfo), + isCurrentSessionTrusted = true, ) // When @@ -74,8 +78,8 @@ class SessionOverviewViewModelTest { .assertLatestState { state -> state == expectedState } .finish() verify { - isCurrentSessionUseCase.execute(A_SESSION_ID) - getDeviceFullInfoUseCase.execute(A_SESSION_ID) + isCurrentSessionUseCase.execute(A_SESSION_ID_1) + getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } } @@ -83,10 +87,11 @@ class SessionOverviewViewModelTest { fun `given current session can be verified when handling verify current session action then self verification event is posted`() { // Given val deviceFullInfo = mockk() - every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) every { isCurrentSessionUseCase.execute(any()) } returns true val verifySessionAction = SessionOverviewAction.VerifySession coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns true + givenCurrentSessionIsTrusted() // When val viewModel = createViewModel() @@ -106,10 +111,11 @@ class SessionOverviewViewModelTest { fun `given current session cannot be verified when handling verify current session action then reset secrets event is posted`() { // Given val deviceFullInfo = mockk() - every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) every { isCurrentSessionUseCase.execute(any()) } returns true val verifySessionAction = SessionOverviewAction.VerifySession coEvery { checkIfCurrentSessionCanBeVerifiedUseCase.execute() } returns false + givenCurrentSessionIsTrusted() // When val viewModel = createViewModel() @@ -129,9 +135,10 @@ class SessionOverviewViewModelTest { fun `given another session when handling verify session action then verify session event is posted`() { // Given val deviceFullInfo = mockk() - every { getDeviceFullInfoUseCase.execute(A_SESSION_ID) } returns flowOf(deviceFullInfo) + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_1) } returns flowOf(deviceFullInfo) every { isCurrentSessionUseCase.execute(any()) } returns false - val verifySessionAction = SessionOverviewAction.VerifySession(A_SESSION_ID) + val verifySessionAction = SessionOverviewAction.VerifySession + givenCurrentSessionIsTrusted() // When val viewModel = createViewModel() @@ -143,4 +150,11 @@ class SessionOverviewViewModelTest { .assertEvent { it is SessionOverviewViewEvent.ShowVerifyOtherSession } .finish() } + + private fun givenCurrentSessionIsTrusted() { + fakeActiveSessionHolder.fakeSession.givenSessionId(A_SESSION_ID_2) + val deviceFullInfo = mockk() + every { deviceFullInfo.roomEncryptionTrustLevel } returns RoomEncryptionTrustLevel.Trusted + every { getDeviceFullInfoUseCase.execute(A_SESSION_ID_2) } returns flowOf(deviceFullInfo) + } } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCaseTest.kt index 25d5766774..f566c8f55e 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCaseTest.kt @@ -107,11 +107,8 @@ class GetCurrentSessionCrossSigningInfoUseCaseTest { } private fun givenSession(deviceId: String): FakeSession { - val sessionParams = mockk() - every { sessionParams.deviceId } returns deviceId - val fakeSession = fakeActiveSessionHolder.fakeSession - fakeSession.givenSessionParams(sessionParams) + fakeSession.givenSessionId(deviceId) return fakeSession } diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt index 35d23e35e8..4171307922 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSession.kt @@ -78,6 +78,13 @@ class FakeSession( every { this@FakeSession.sessionParams } returns sessionParams } + fun givenSessionId(sessionId: String): SessionParams { + val sessionParams = mockk() + every { sessionParams.deviceId } returns sessionId + givenSessionParams(sessionParams) + return sessionParams + } + /** * Do not forget to call mockkStatic("org.matrix.android.sdk.flow.FlowSessionKt") in the setup method of the tests. */ From 17bb14c1dc3f25f8aa9c732c06f150fc45be31f9 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Fri, 16 Sep 2022 15:05:55 +0200 Subject: [PATCH 058/187] Fixing coding style issues --- .../vector/app/features/settings/devices/DevicesViewModel.kt | 2 +- .../settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt | 2 +- .../devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt | 4 ++-- .../GetCurrentSessionCrossSigningInfoUseCaseTest.kt | 1 - 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt index 95b852b809..d30d6ee270 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt @@ -34,8 +34,8 @@ import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.PublishDataSource import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.login.ReAuthHelper -import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase +import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase import im.vector.lib.core.utils.flow.throttleFirst import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.combine diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt index bb2c4f4c6a..8b343f5f90 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCase.kt @@ -19,9 +19,9 @@ package im.vector.app.features.settings.devices.v2.overview import androidx.lifecycle.asFlow import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.features.settings.devices.v2.DeviceFullInfo +import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase -import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.emptyFlow diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt index 33a83cd590..3ef1c5a515 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/GetDeviceFullInfoUseCaseTest.kt @@ -18,11 +18,11 @@ package im.vector.app.features.settings.devices.v2.overview import androidx.lifecycle.MutableLiveData import androidx.lifecycle.asFlow -import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo import im.vector.app.features.settings.devices.v2.DeviceFullInfo +import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase +import im.vector.app.features.settings.devices.v2.verification.CurrentSessionCrossSigningInfo import im.vector.app.features.settings.devices.v2.verification.GetCurrentSessionCrossSigningInfoUseCase import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase -import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.fakes.FakeFlowLiveDataConversions import im.vector.app.test.fakes.givenAsFlow diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCaseTest.kt index f566c8f55e..356d771d39 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/verification/GetCurrentSessionCrossSigningInfoUseCaseTest.kt @@ -30,7 +30,6 @@ import kotlinx.coroutines.test.runTest import org.junit.After import org.junit.Before import org.junit.Test -import org.matrix.android.sdk.api.auth.data.SessionParams import org.matrix.android.sdk.api.session.crypto.crosssigning.MXCrossSigningInfo import org.matrix.android.sdk.api.util.toOptional From aa7f7d7111904bea73df735700ef02d6ae177da3 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 10:00:34 +0200 Subject: [PATCH 059/187] Fix after rebase --- .../devices/v2/overview/SessionOverviewViewModel.kt | 7 +++++-- .../devices/v2/overview/SessionOverviewViewModelTest.kt | 3 +++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index 40a78a4fd3..4756e1e10e 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -21,6 +21,7 @@ import com.airbnb.mvrx.Success import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel @@ -35,6 +36,7 @@ import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel class SessionOverviewViewModel @AssistedInject constructor( @Assisted val initialState: SessionOverviewViewState, + private val activeSessionHolder: ActiveSessionHolder, private val isCurrentSessionUseCase: IsCurrentSessionUseCase, private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase, private val checkIfCurrentSessionCanBeVerifiedUseCase: CheckIfCurrentSessionCanBeVerifiedUseCase, @@ -85,10 +87,11 @@ class SessionOverviewViewModel @AssistedInject constructor( } private fun handleVerifySessionAction() = withState { viewState -> - if (isCurrentSession(viewState.deviceId)) { + val deviceId = viewState.deviceId + if (isCurrentSession(deviceId)) { handleVerifyCurrentSession() } else { - handleVerifyOtherSession(verifySession.deviceId) + handleVerifyOtherSession(deviceId) } } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index 3ba3e616df..857fa94ade 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -21,6 +21,7 @@ import com.airbnb.mvrx.test.MvRxTestRule import im.vector.app.features.settings.devices.v2.DeviceFullInfo import im.vector.app.features.settings.devices.v2.IsCurrentSessionUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase +import im.vector.app.test.fakes.FakeActiveSessionHolder import im.vector.app.test.test import im.vector.app.test.testDispatcher import io.mockk.coEvery @@ -44,12 +45,14 @@ class SessionOverviewViewModelTest { private val args = SessionOverviewArgs( deviceId = A_SESSION_ID_1 ) + private val fakeActiveSessionHolder = FakeActiveSessionHolder() private val isCurrentSessionUseCase = mockk() private val getDeviceFullInfoUseCase = mockk() private val checkIfCurrentSessionCanBeVerifiedUseCase = mockk() private fun createViewModel() = SessionOverviewViewModel( initialState = SessionOverviewViewState(args), + activeSessionHolder = fakeActiveSessionHolder.instance, isCurrentSessionUseCase = isCurrentSessionUseCase, getDeviceFullInfoUseCase = getDeviceFullInfoUseCase, checkIfCurrentSessionCanBeVerifiedUseCase = checkIfCurrentSessionCanBeVerifiedUseCase, From 72637b465f3dca27bb6801c452a2e26757e3624f Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 11:23:11 +0200 Subject: [PATCH 060/187] Using viewState value to check if it is current session --- .../settings/devices/v2/overview/SessionOverviewViewModel.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index 4756e1e10e..69556e039e 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -87,11 +87,10 @@ class SessionOverviewViewModel @AssistedInject constructor( } private fun handleVerifySessionAction() = withState { viewState -> - val deviceId = viewState.deviceId - if (isCurrentSession(deviceId)) { + if (viewState.isCurrentSession) { handleVerifyCurrentSession() } else { - handleVerifyOtherSession(deviceId) + handleVerifyOtherSession(viewState.deviceId) } } From 943ec7ee7505ee99c96579590923a1474953a97e Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 11:29:39 +0200 Subject: [PATCH 061/187] Reducing argument number in session info view update method --- .../v2/overview/SessionOverviewFragment.kt | 38 +++++++++---------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index db293e88a9..73991c5f20 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -35,7 +35,6 @@ import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.DrawableProvider import im.vector.app.databinding.FragmentSessionOverviewBinding import im.vector.app.features.crypto.recover.SetupMode -import im.vector.app.features.settings.devices.v2.DeviceFullInfo import im.vector.app.features.settings.devices.v2.list.SessionInfoViewState import javax.inject.Inject @@ -107,11 +106,7 @@ class SessionOverviewFragment : override fun invalidate() = withState(viewModel) { state -> updateToolbar(state.isCurrentSession) updateEntryDetails(state.deviceId) - if (state.deviceInfo is Success) { - renderSessionInfo(state.isCurrentSession, state.deviceInfo.invoke(), state.isCurrentSessionTrusted) - } else { - hideSessionInfo() - } + updateSessionInfo(state) } private fun updateToolbar(isCurrentSession: Boolean) { @@ -127,21 +122,22 @@ class SessionOverviewFragment : } } - private fun renderSessionInfo( - isCurrentSession: Boolean, - deviceFullInfo: DeviceFullInfo, - isCurrentSessionTrusted: Boolean, - ) { - views.sessionOverviewInfo.isVisible = true - val viewState = SessionInfoViewState( - isCurrentSession = isCurrentSession, - deviceFullInfo = deviceFullInfo, - isVerifyButtonVisible = isCurrentSession || isCurrentSessionTrusted, - isDetailsButtonVisible = false, - isLearnMoreLinkVisible = true, - isLastSeenDetailsVisible = true, - ) - views.sessionOverviewInfo.render(viewState, dateFormatter, drawableProvider, colorProvider) + private fun updateSessionInfo(viewState: SessionOverviewViewState) { + if (viewState.deviceInfo is Success) { + views.sessionOverviewInfo.isVisible = true + val isCurrentSession = viewState.isCurrentSession + val infoViewState = SessionInfoViewState( + isCurrentSession = isCurrentSession, + deviceFullInfo = viewState.deviceInfo.invoke(), + isVerifyButtonVisible = isCurrentSession || viewState.isCurrentSessionTrusted, + isDetailsButtonVisible = false, + isLearnMoreLinkVisible = true, + isLastSeenDetailsVisible = true, + ) + views.sessionOverviewInfo.render(infoViewState, dateFormatter, drawableProvider, colorProvider) + } else { + hideSessionInfo() + } } private fun hideSessionInfo() { From 2168362a8b5ff1de59de739c7b58d83a415fa8c2 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Tue, 20 Sep 2022 10:06:16 +0100 Subject: [PATCH 062/187] including appcompat (instead of the support library) to fix colorPrimary attribute compiliation issues --- library/external/dialpad/build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/external/dialpad/build.gradle b/library/external/dialpad/build.gradle index 1f91deeeb5..fade8ddf30 100644 --- a/library/external/dialpad/build.gradle +++ b/library/external/dialpad/build.gradle @@ -19,6 +19,10 @@ android { } } +dependencies { + implementation libs.androidx.appCompat +} + afterEvaluate { tasks.findAll { it.name.startsWith("lint") }.each { it.enabled = false From 3ea054f8e1ee534e9bfefe8c9f5aa5d3355fedbf Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 20 Sep 2022 15:06:52 +0300 Subject: [PATCH 063/187] Fix unit test. --- .../devices/v2/DevicesViewModelTest.kt | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt index 741fb15cc3..517f315553 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt @@ -16,6 +16,7 @@ package im.vector.app.features.settings.devices.v2 +import android.os.SystemClock import com.airbnb.mvrx.Success import com.airbnb.mvrx.test.MvRxTestRule import im.vector.app.test.fakes.FakeActiveSessionHolder @@ -27,11 +28,16 @@ import io.mockk.coVerify import io.mockk.every import io.mockk.just import io.mockk.mockk +import io.mockk.mockkStatic import io.mockk.runs +import io.mockk.unmockkAll import io.mockk.verify import kotlinx.coroutines.flow.flowOf +import org.junit.After +import org.junit.Before import org.junit.Rule import org.junit.Test +import org.matrix.android.sdk.api.session.crypto.crosssigning.DeviceTrustLevel import org.matrix.android.sdk.api.session.crypto.model.CryptoDeviceInfo import org.matrix.android.sdk.api.session.crypto.model.RoomEncryptionTrustLevel @@ -57,6 +63,17 @@ class DevicesViewModelTest { ) } + @Before + fun setup() { + mockkStatic(SystemClock::class) + every { SystemClock.elapsedRealtime() } returns 1234 + } + + @After + fun tearDown() { + unmockkAll() + } + @Test fun `given the viewModel when initializing it then verification listener is added`() { // Given @@ -164,8 +181,10 @@ class DevicesViewModelTest { private fun givenDeviceFullInfoList(): List { val verifiedCryptoDeviceInfo = mockk() every { verifiedCryptoDeviceInfo.isVerified } returns true + every { verifiedCryptoDeviceInfo.trustLevel } returns DeviceTrustLevel(crossSigningVerified = true, locallyVerified = true) val unverifiedCryptoDeviceInfo = mockk() every { unverifiedCryptoDeviceInfo.isVerified } returns false + every { unverifiedCryptoDeviceInfo.trustLevel } returns DeviceTrustLevel(crossSigningVerified = false, locallyVerified = false) val deviceFullInfo1 = DeviceFullInfo( deviceInfo = mockk(), From 4ab798f88ddf560534eef74e90d3a12173614d22 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 21 Sep 2022 14:16:51 +0300 Subject: [PATCH 064/187] Code review fixes. --- .../v2/list/OtherSessionsController.kt | 31 +++++++++++-------- .../v2/list/SecurityRecommendationView.kt | 5 +++ .../v2/othersessions/OtherSessionsActivity.kt | 2 ++ .../v2/othersessions/OtherSessionsFragment.kt | 3 +- 4 files changed, 26 insertions(+), 15 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt index bcf6e87575..afa640fb9a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/OtherSessionsController.kt @@ -78,19 +78,24 @@ class OtherSessionsController @Inject constructor( } private fun calculateDescription(device: DeviceFullInfo, formattedLastActivityDate: String): String { - return if (device.isInactive) { - stringProvider.getQuantityString( - R.plurals.device_manager_other_sessions_description_inactive, - SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS, - SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS, - formattedLastActivityDate - ) - } else if (device.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Trusted) { - stringProvider.getString(R.string.device_manager_other_sessions_description_verified, formattedLastActivityDate) - } else if (device.isCurrentDevice) { - stringProvider.getString(R.string.device_manager_other_sessions_description_unverified_current_session) - } else { - stringProvider.getString(R.string.device_manager_other_sessions_description_unverified, formattedLastActivityDate) + return when { + device.isInactive -> { + stringProvider.getQuantityString( + R.plurals.device_manager_other_sessions_description_inactive, + SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS, + SESSION_IS_MARKED_AS_INACTIVE_AFTER_DAYS, + formattedLastActivityDate + ) + } + device.roomEncryptionTrustLevel == RoomEncryptionTrustLevel.Trusted -> { + stringProvider.getString(R.string.device_manager_other_sessions_description_verified, formattedLastActivityDate) + } + device.isCurrentDevice -> { + stringProvider.getString(R.string.device_manager_other_sessions_description_unverified_current_session) + } + else -> { + stringProvider.getString(R.string.device_manager_other_sessions_description_unverified, formattedLastActivityDate) + } } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SecurityRecommendationView.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SecurityRecommendationView.kt index c4d86af8c3..07202274ad 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SecurityRecommendationView.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/list/SecurityRecommendationView.kt @@ -87,4 +87,9 @@ class SecurityRecommendationView @JvmOverloads constructor( setDescription(viewState.description) setCount(viewState.sessionsCount) } + + override fun onDetachedFromWindow() { + super.onDetachedFromWindow() + callback = null + } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsActivity.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsActivity.kt index a2c9da6ea0..f56b838215 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsActivity.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsActivity.kt @@ -20,6 +20,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.view.View +import androidx.annotation.StringRes import com.airbnb.mvrx.Mavericks import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment @@ -46,6 +47,7 @@ class OtherSessionsActivity : SimpleFragmentActivity() { companion object { fun newIntent( context: Context, + @StringRes titleResourceId: Int, defaultFilter: DeviceManagerFilterType, includeCurrentSession: Boolean, diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt index 26cd74a380..5734b04089 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsFragment.kt @@ -59,8 +59,7 @@ class OtherSessionsFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) - views.otherSessionsToolbar.title = getString(args.titleResourceId) - setupToolbar(views.otherSessionsToolbar).allowBack() + setupToolbar(views.otherSessionsToolbar).setTitle(args.titleResourceId).allowBack() observeViewEvents() initFilterView() } From 8de9ef8c7df3356f4b16fbd694b8f86ec82b09ed Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 21 Sep 2022 14:30:24 +0300 Subject: [PATCH 065/187] Code review fixes. --- .../settings/devices/v2/VectorSettingsDevicesFragment.kt | 6 +++--- .../devices/v2/VectorSettingsDevicesViewNavigator.kt | 4 ++-- .../devices/v2/othersessions/OtherSessionsActivity.kt | 4 ++-- .../settings/devices/v2/othersessions/OtherSessionsArgs.kt | 4 +++- .../devices/v2/othersessions/OtherSessionsViewModel.kt | 2 +- .../devices/v2/othersessions/OtherSessionsViewState.kt | 4 ++-- .../features/settings/devices/v2/DevicesViewModelTest.kt | 2 -- .../devices/v2/VectorSettingsDevicesViewNavigatorTest.kt | 4 ++-- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt index da1a9a2fbd..e1888d0672 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesFragment.kt @@ -135,7 +135,7 @@ class VectorSettingsDevicesFragment : requireActivity(), R.string.device_manager_header_section_security_recommendations_title, DeviceManagerFilterType.UNVERIFIED, - includeCurrentSession = true + excludeCurrentDevice = false ) } } @@ -145,7 +145,7 @@ class VectorSettingsDevicesFragment : requireActivity(), R.string.device_manager_header_section_security_recommendations_title, DeviceManagerFilterType.INACTIVE, - includeCurrentSession = true + excludeCurrentDevice = false ) } } @@ -290,7 +290,7 @@ class VectorSettingsDevicesFragment : context = requireActivity(), titleResourceId = R.string.device_manager_sessions_other_title, defaultFilter = DeviceManagerFilterType.ALL_SESSIONS, - includeCurrentSession = false + excludeCurrentDevice = true ) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt index 991de805e7..47e697822b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigator.kt @@ -32,10 +32,10 @@ class VectorSettingsDevicesViewNavigator @Inject constructor() { context: Context, titleResourceId: Int, defaultFilter: DeviceManagerFilterType, - includeCurrentSession: Boolean, + excludeCurrentDevice: Boolean, ) { context.startActivity( - OtherSessionsActivity.newIntent(context, titleResourceId, defaultFilter, includeCurrentSession) + OtherSessionsActivity.newIntent(context, titleResourceId, defaultFilter, excludeCurrentDevice) ) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsActivity.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsActivity.kt index f56b838215..f146f77690 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsActivity.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsActivity.kt @@ -50,10 +50,10 @@ class OtherSessionsActivity : SimpleFragmentActivity() { @StringRes titleResourceId: Int, defaultFilter: DeviceManagerFilterType, - includeCurrentSession: Boolean, + excludeCurrentDevice: Boolean, ): Intent { return Intent(context, OtherSessionsActivity::class.java).apply { - putExtra(Mavericks.KEY_ARG, OtherSessionsArgs(titleResourceId, defaultFilter, includeCurrentSession)) + putExtra(Mavericks.KEY_ARG, OtherSessionsArgs(titleResourceId, defaultFilter, excludeCurrentDevice)) } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsArgs.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsArgs.kt index 55a7000c4f..61f89eaffa 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsArgs.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsArgs.kt @@ -17,12 +17,14 @@ package im.vector.app.features.settings.devices.v2.othersessions import android.os.Parcelable +import androidx.annotation.StringRes import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType import kotlinx.parcelize.Parcelize @Parcelize data class OtherSessionsArgs( + @StringRes val titleResourceId: Int, val defaultFilter: DeviceManagerFilterType, - val includeCurrentSession: Boolean, + val excludeCurrentDevice: Boolean, ) : Parcelable diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt index 2ca24dd92a..e52953e2b6 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewModel.kt @@ -55,7 +55,7 @@ class OtherSessionsViewModel @AssistedInject constructor( observeDevicesJob?.cancel() observeDevicesJob = getDeviceFullInfoListUseCase.execute( filterType = currentFilter, - excludeCurrentDevice = !initialState.includeCurrentSession + excludeCurrentDevice = initialState.excludeCurrentDevice ) .execute { async -> copy( diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewState.kt index cb30490845..5256a9b27a 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/othersessions/OtherSessionsViewState.kt @@ -25,8 +25,8 @@ import im.vector.app.features.settings.devices.v2.filter.DeviceManagerFilterType data class OtherSessionsViewState( val devices: Async> = Uninitialized, val currentFilter: DeviceManagerFilterType = DeviceManagerFilterType.ALL_SESSIONS, - val includeCurrentSession: Boolean = false, + val excludeCurrentDevice: Boolean = false, ) : MavericksState { - constructor(args: OtherSessionsArgs) : this(includeCurrentSession = args.includeCurrentSession) + constructor(args: OtherSessionsArgs) : this(excludeCurrentDevice = args.excludeCurrentDevice) } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt index 517f315553..bc5331568c 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/DevicesViewModelTest.kt @@ -180,10 +180,8 @@ class DevicesViewModelTest { */ private fun givenDeviceFullInfoList(): List { val verifiedCryptoDeviceInfo = mockk() - every { verifiedCryptoDeviceInfo.isVerified } returns true every { verifiedCryptoDeviceInfo.trustLevel } returns DeviceTrustLevel(crossSigningVerified = true, locallyVerified = true) val unverifiedCryptoDeviceInfo = mockk() - every { unverifiedCryptoDeviceInfo.isVerified } returns false every { unverifiedCryptoDeviceInfo.trustLevel } returns DeviceTrustLevel(crossSigningVerified = false, locallyVerified = false) val deviceFullInfo1 = DeviceFullInfo( diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigatorTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigatorTest.kt index 7b8b6ee82d..ec8019384a 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigatorTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/VectorSettingsDevicesViewNavigatorTest.kt @@ -80,9 +80,9 @@ class VectorSettingsDevicesViewNavigatorTest { return intent } - private fun givenIntentForOtherSessions(titleResourceId: Int, defaultFilter: DeviceManagerFilterType, includeCurrentSession: Boolean): Intent { + private fun givenIntentForOtherSessions(titleResourceId: Int, defaultFilter: DeviceManagerFilterType, excludeCurrentDevice: Boolean): Intent { val intent = mockk() - every { OtherSessionsActivity.newIntent(context.instance, titleResourceId, defaultFilter, includeCurrentSession) } returns intent + every { OtherSessionsActivity.newIntent(context.instance, titleResourceId, defaultFilter, excludeCurrentDevice) } returns intent return intent } } From 7f31098ba192e2c17aa699c1e87dcc46e249e0e0 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 21 Sep 2022 14:25:26 +0100 Subject: [PATCH 066/187] lifting the sync timeout to the matrix configuration --- .../android/sdk/api/MatrixConfiguration.kt | 4 ++++ .../org/matrix/android/sdk/api/SyncConfig.kt | 24 +++++++++++++++++++ .../internal/session/sync/job/SyncThread.kt | 7 +++--- 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/SyncConfig.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt index 893e90fb3e..3b4b3b624d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt @@ -70,4 +70,8 @@ data class MatrixConfiguration( * List of network interceptors, they will be added when building an OkHttp client. */ val networkInterceptors: List = emptyList(), + /** + * Sync configuration. + */ + val syncConfig: SyncConfig = SyncConfig() ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/SyncConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/SyncConfig.kt new file mode 100644 index 0000000000..b5547896d4 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/SyncConfig.kt @@ -0,0 +1,24 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.api + +data class SyncConfig( + /** + * Time to keep sync connection alive for before making another request in milliseconds. + */ + val longPollTimeout: Long = 30_000L +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt index b47b215655..d3f2a3f044 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/sync/job/SyncThread.kt @@ -30,6 +30,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.SharedFlow import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import org.matrix.android.sdk.api.MatrixConfiguration import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.failure.Failure import org.matrix.android.sdk.api.failure.isTokenError @@ -52,7 +53,6 @@ import javax.inject.Inject import kotlin.concurrent.schedule private const val RETRY_WAIT_TIME_MS = 10_000L -private const val DEFAULT_LONG_POOL_TIMEOUT = 30_000L private val loggerTag = LoggerTag("SyncThread", LoggerTag.SYNC) @@ -61,7 +61,8 @@ internal class SyncThread @Inject constructor( private val networkConnectivityChecker: NetworkConnectivityChecker, private val backgroundDetectionObserver: BackgroundDetectionObserver, private val activeCallHandler: ActiveCallHandler, - private val lightweightSettingsStorage: DefaultLightweightSettingsStorage + private val lightweightSettingsStorage: DefaultLightweightSettingsStorage, + private val matrixConfiguration: MatrixConfiguration, ) : Thread("Matrix-SyncThread"), NetworkConnectivityChecker.Listener, BackgroundDetectionObserver.Listener { private var state: SyncState = SyncState.Idle @@ -181,7 +182,7 @@ internal class SyncThread @Inject constructor( val timeout = when { previousSyncResponseHasToDevice -> 0L /* Force timeout to 0 */ afterPause -> 0L /* No timeout after a pause */ - else -> DEFAULT_LONG_POOL_TIMEOUT + else -> matrixConfiguration.syncConfig.longPollTimeout } Timber.tag(loggerTag.value).d("Execute sync request with timeout $timeout") val presence = lightweightSettingsStorage.getSyncPresenceStatus() From 9ab78c93e2e8fe4ed618926473d734ad65906175 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 21 Sep 2022 14:36:27 +0100 Subject: [PATCH 067/187] reducing sync timeout for instrumentation tests to speed them up --- .../java/org/matrix/android/sdk/common/CommonTestHelper.kt | 4 +++- .../java/im/vector/app/core/utils/TestMatrixHelper.kt | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt index a78953caac..d30cee0eab 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt @@ -36,6 +36,7 @@ import org.junit.Assert.assertNotNull import org.junit.Assert.assertTrue import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.MatrixConfiguration +import org.matrix.android.sdk.api.SyncConfig import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig import org.matrix.android.sdk.api.auth.registration.RegistrationResult import org.matrix.android.sdk.api.session.Session @@ -103,7 +104,8 @@ class CommonTestHelper internal constructor(context: Context) { context, MatrixConfiguration( applicationFlavor = "TestFlavor", - roomDisplayNameFallbackProvider = TestRoomDisplayNameFallbackProvider() + roomDisplayNameFallbackProvider = TestRoomDisplayNameFallbackProvider(), + syncConfig = SyncConfig(longPollTimeout = 5_000L) ) ) } diff --git a/vector-app/src/androidTest/java/im/vector/app/core/utils/TestMatrixHelper.kt b/vector-app/src/androidTest/java/im/vector/app/core/utils/TestMatrixHelper.kt index 48fc1343b1..9bdb0f863a 100644 --- a/vector-app/src/androidTest/java/im/vector/app/core/utils/TestMatrixHelper.kt +++ b/vector-app/src/androidTest/java/im/vector/app/core/utils/TestMatrixHelper.kt @@ -20,11 +20,13 @@ import androidx.test.platform.app.InstrumentationRegistry import im.vector.app.features.room.VectorRoomDisplayNameFallbackProvider import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.MatrixConfiguration +import org.matrix.android.sdk.api.SyncConfig fun getMatrixInstance(): Matrix { val context = InstrumentationRegistry.getInstrumentation().targetContext val configuration = MatrixConfiguration( - roomDisplayNameFallbackProvider = VectorRoomDisplayNameFallbackProvider(context) + roomDisplayNameFallbackProvider = VectorRoomDisplayNameFallbackProvider(context), + syncConfig = SyncConfig(longPollTimeout = 5_000L) ) return Matrix(context, configuration) } From d75e37966c318058ca399b99a1ae099e384f93d8 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 21 Sep 2022 15:37:16 +0100 Subject: [PATCH 068/187] adding changelog entry --- changelog.d/7198.sdk | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7198.sdk diff --git a/changelog.d/7198.sdk b/changelog.d/7198.sdk new file mode 100644 index 0000000000..115b8d6113 --- /dev/null +++ b/changelog.d/7198.sdk @@ -0,0 +1 @@ +Allow the sync timeout to be configured (mainly useful for testing) From 600588dbbba66b736e9b659b735e85de56035d24 Mon Sep 17 00:00:00 2001 From: Adam Brown Date: Wed, 21 Sep 2022 16:37:31 +0100 Subject: [PATCH 069/187] adding trailing commas --- .../java/org/matrix/android/sdk/common/CommonTestHelper.kt | 2 +- .../main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt | 2 +- .../src/main/java/org/matrix/android/sdk/api/SyncConfig.kt | 2 +- .../java/im/vector/app/core/utils/TestMatrixHelper.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt index d30cee0eab..b179c6027e 100644 --- a/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt +++ b/matrix-sdk-android/src/androidTest/java/org/matrix/android/sdk/common/CommonTestHelper.kt @@ -105,7 +105,7 @@ class CommonTestHelper internal constructor(context: Context) { MatrixConfiguration( applicationFlavor = "TestFlavor", roomDisplayNameFallbackProvider = TestRoomDisplayNameFallbackProvider(), - syncConfig = SyncConfig(longPollTimeout = 5_000L) + syncConfig = SyncConfig(longPollTimeout = 5_000L), ) ) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt index 3b4b3b624d..7119563617 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/MatrixConfiguration.kt @@ -73,5 +73,5 @@ data class MatrixConfiguration( /** * Sync configuration. */ - val syncConfig: SyncConfig = SyncConfig() + val syncConfig: SyncConfig = SyncConfig(), ) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/SyncConfig.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/SyncConfig.kt index b5547896d4..a9753e2407 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/SyncConfig.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/SyncConfig.kt @@ -20,5 +20,5 @@ data class SyncConfig( /** * Time to keep sync connection alive for before making another request in milliseconds. */ - val longPollTimeout: Long = 30_000L + val longPollTimeout: Long = 30_000L, ) diff --git a/vector-app/src/androidTest/java/im/vector/app/core/utils/TestMatrixHelper.kt b/vector-app/src/androidTest/java/im/vector/app/core/utils/TestMatrixHelper.kt index 9bdb0f863a..d8873a71a4 100644 --- a/vector-app/src/androidTest/java/im/vector/app/core/utils/TestMatrixHelper.kt +++ b/vector-app/src/androidTest/java/im/vector/app/core/utils/TestMatrixHelper.kt @@ -26,7 +26,7 @@ fun getMatrixInstance(): Matrix { val context = InstrumentationRegistry.getInstrumentation().targetContext val configuration = MatrixConfiguration( roomDisplayNameFallbackProvider = VectorRoomDisplayNameFallbackProvider(context), - syncConfig = SyncConfig(longPollTimeout = 5_000L) + syncConfig = SyncConfig(longPollTimeout = 5_000L), ) return Matrix(context, configuration) } From 44f6e66efbd040349bd142dfcc5c4b0fa332ac3e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Sep 2022 23:10:46 +0000 Subject: [PATCH 070/187] Bump fragment from 1.5.2 to 1.5.3 Bumps `fragment` from 1.5.2 to 1.5.3. Updates `fragment-ktx` from 1.5.2 to 1.5.3 Updates `fragment-testing` from 1.5.2 to 1.5.3 --- updated-dependencies: - dependency-name: androidx.fragment:fragment-ktx dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: androidx.fragment:fragment-testing dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies.gradle b/dependencies.gradle index 9641a63f26..6fcf15760b 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -30,7 +30,7 @@ def bigImageViewer = "1.8.1" def jjwt = "0.11.5" def vanniktechEmoji = "0.15.0" -def fragment = "1.5.2" +def fragment = "1.5.3" // Testing def mockk = "1.12.3" // We need to use 1.12.3 to have mocking in androidTest until a new version is released: https://github.com/mockk/mockk/issues/819 From fabfe36eded8a37e7235b86cb96c423e4da9e9ef Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 22 Sep 2022 10:31:31 +0200 Subject: [PATCH 071/187] Update versions to 1.5.2 --- matrix-sdk-android/build.gradle | 2 +- vector-app/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 65f8baee7b..5c800f720e 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -60,7 +60,7 @@ android { // that the app's state is completely cleared between tests. testInstrumentationRunnerArguments clearPackageData: 'true' - buildConfigField "String", "SDK_VERSION", "\"1.5.0\"" + buildConfigField "String", "SDK_VERSION", "\"1.5.2\"" buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\"" buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\"" diff --git a/vector-app/build.gradle b/vector-app/build.gradle index dacd1416fd..f3618f030d 100644 --- a/vector-app/build.gradle +++ b/vector-app/build.gradle @@ -36,7 +36,7 @@ ext.versionMinor = 5 // Note: even values are reserved for regular release, odd values for hotfix release. // When creating a hotfix, you should decrease the value, since the current value // is the value for the next regular release. -ext.versionPatch = 0 +ext.versionPatch = 2 static def getGitTimestamp() { def cmd = 'git show -s --format=%ct' From b2e7cc220801ac18d85b3b79c9c28deecc57113e Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 22 Sep 2022 15:18:20 +0300 Subject: [PATCH 072/187] Extend user agent by adding device manufacturer and model to the beginning. --- .../sdk/internal/network/UserAgentHolder.kt | 77 ++++++++++--------- 1 file changed, 41 insertions(+), 36 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt index 28d96dfce7..e0611a1de6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt @@ -17,10 +17,11 @@ package org.matrix.android.sdk.internal.network import android.content.Context +import android.os.Build import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.api.MatrixConfiguration +import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.internal.di.MatrixScope -import timber.log.Timber import javax.inject.Inject @MatrixScope @@ -38,51 +39,55 @@ internal class UserAgentHolder @Inject constructor( /** * Create an user agent with the application version. - * Ex: Element/1.0.0 (Linux; U; Android 6.0.1; SM-A510F Build/MMB29; Flavour GPlay; MatrixAndroidSdk2 1.0) + * Ex: Element/1.5.0 (Xiaomi; Mi 9T; Android 11; RKQ1.200826.002; Flavour GooglePlay; MatrixAndroidSdk2 1.5.0) * * @param flavorDescription the flavor description */ private fun setApplicationFlavor(flavorDescription: String) { - var appName = "" - var appVersion = "" + val appPackageName = context.applicationContext.packageName + val pm = context.packageManager - try { - val appPackageName = context.applicationContext.packageName - val pm = context.packageManager - val appInfo = pm.getApplicationInfo(appPackageName, 0) - appName = pm.getApplicationLabel(appInfo).toString() + val appName = tryOrNull { pm.getApplicationLabel(pm.getApplicationInfo(appPackageName, 0)).toString() } + ?.takeIf { + it.matches("\\A\\p{ASCII}*\\z".toRegex()) + } + ?: run { + // Use appPackageName instead of appName if appName contains any non-ASCII character + appPackageName + } + val appVersion = tryOrNull { pm.getPackageInfo(context.applicationContext.packageName, 0).versionName } - val pkgInfo = pm.getPackageInfo(context.applicationContext.packageName, 0) - appVersion = pkgInfo.versionName ?: "" + val deviceManufacturer = Build.MANUFACTURER + val deviceModel = Build.MODEL + val androidVersion = Build.VERSION.RELEASE + val deviceBuildId = Build.DISPLAY + val matrixSdkVersion = BuildConfig.SDK_VERSION - // Use appPackageName instead of appName if appName contains any non-ASCII character - if (!appName.matches("\\A\\p{ASCII}*\\z".toRegex())) { - appName = appPackageName - } - } catch (e: Exception) { - Timber.e(e, "## initUserAgent() : failed") - } - - val systemUserAgent = System.getProperty("http.agent") - - // cannot retrieve the application version - if (appName.isEmpty() || appVersion.isEmpty()) { - if (null == systemUserAgent) { - userAgent = "Java" + System.getProperty("java.version") - } + if (appName.isNullOrEmpty() || appVersion.isNullOrEmpty()) { + userAgent = tryOrNull { System.getProperty("http.agent") } ?: ("Java" + System.getProperty("java.version")) return } - // if there is no user agent or cannot parse it - if (null == systemUserAgent || systemUserAgent.lastIndexOf(")") == -1 || !systemUserAgent.contains("(")) { - userAgent = (appName + "/" + appVersion + " ( Flavour " + flavorDescription + - "; MatrixAndroidSdk2 " + BuildConfig.SDK_VERSION + ")") - } else { - // update - userAgent = appName + "/" + appVersion + " " + - systemUserAgent.substring(systemUserAgent.indexOf("("), systemUserAgent.lastIndexOf(")") - 1) + - "; Flavour " + flavorDescription + - "; MatrixAndroidSdk2 " + BuildConfig.SDK_VERSION + ")" + userAgent = buildString { + append(appName) + append("/") + append(appVersion) + append(" (") + append(deviceManufacturer) + append("; ") + append(deviceModel) + append("; ") + append("Android ") + append(androidVersion) + append("; ") + append(deviceBuildId) + append("; ") + append("Flavour ") + append(flavorDescription) + append("; ") + append("MatrixAndroidSdk2 ") + append(matrixSdkVersion) + append(")") } } } From 8b3eaf10e11dbc02c065c4694310f9d8f12f9b21 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 22 Sep 2022 15:25:31 +0300 Subject: [PATCH 073/187] Add changelog. --- changelog.d/7209.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7209.feature diff --git a/changelog.d/7209.feature b/changelog.d/7209.feature new file mode 100644 index 0000000000..6375f5e495 --- /dev/null +++ b/changelog.d/7209.feature @@ -0,0 +1 @@ +[Device Manager] Extend user agent to include device information From ea78f504d713f005721c97db1c3dbc688611da1e Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 22 Sep 2022 15:28:26 +0300 Subject: [PATCH 074/187] Small refactoring. --- .../android/sdk/internal/network/UserAgentHolder.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt index e0611a1de6..92d00c3895 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt @@ -56,6 +56,11 @@ internal class UserAgentHolder @Inject constructor( appPackageName } val appVersion = tryOrNull { pm.getPackageInfo(context.applicationContext.packageName, 0).versionName } + + if (appName.isNullOrEmpty() || appVersion.isNullOrEmpty()) { + userAgent = tryOrNull { System.getProperty("http.agent") } ?: ("Java" + System.getProperty("java.version")) + return + } val deviceManufacturer = Build.MANUFACTURER val deviceModel = Build.MODEL @@ -63,11 +68,6 @@ internal class UserAgentHolder @Inject constructor( val deviceBuildId = Build.DISPLAY val matrixSdkVersion = BuildConfig.SDK_VERSION - if (appName.isNullOrEmpty() || appVersion.isNullOrEmpty()) { - userAgent = tryOrNull { System.getProperty("http.agent") } ?: ("Java" + System.getProperty("java.version")) - return - } - userAgent = buildString { append(appName) append("/") From c37a6842fe83f852037cd4caad5639106dda17e1 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Thu, 22 Sep 2022 15:53:29 +0300 Subject: [PATCH 075/187] Update format to be consistent with Element iOS. --- .../matrix/android/sdk/internal/network/UserAgentHolder.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt index 92d00c3895..58231badb6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt @@ -39,7 +39,7 @@ internal class UserAgentHolder @Inject constructor( /** * Create an user agent with the application version. - * Ex: Element/1.5.0 (Xiaomi; Mi 9T; Android 11; RKQ1.200826.002; Flavour GooglePlay; MatrixAndroidSdk2 1.5.0) + * Ex: Element/1.5.0 (Xiaomi Mi 9T; Android 11; RKQ1.200826.002; Flavour GooglePlay; MatrixAndroidSdk2 1.5.0) * * @param flavorDescription the flavor description */ @@ -56,7 +56,7 @@ internal class UserAgentHolder @Inject constructor( appPackageName } val appVersion = tryOrNull { pm.getPackageInfo(context.applicationContext.packageName, 0).versionName } - + if (appName.isNullOrEmpty() || appVersion.isNullOrEmpty()) { userAgent = tryOrNull { System.getProperty("http.agent") } ?: ("Java" + System.getProperty("java.version")) return @@ -74,7 +74,7 @@ internal class UserAgentHolder @Inject constructor( append(appVersion) append(" (") append(deviceManufacturer) - append("; ") + append(" ") append(deviceModel) append("; ") append("Android ") From 2aa9382fbad21eac0f227475990eb70fa840322d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Sep 2022 14:31:16 +0000 Subject: [PATCH 076/187] Bump android-connector from 2.0.1 to 2.1.0 Bumps [android-connector](https://github.com/UnifiedPush/android-connector) from 2.0.1 to 2.1.0. - [Release notes](https://github.com/UnifiedPush/android-connector/releases) - [Commits](https://github.com/UnifiedPush/android-connector/compare/2.0.1...2.1.0) --- updated-dependencies: - dependency-name: com.github.UnifiedPush:android-connector dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- vector/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/build.gradle b/vector/build.gradle index 740f2710c0..c0ff2009f5 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -230,7 +230,7 @@ dependencies { } // UnifiedPush - implementation 'com.github.UnifiedPush:android-connector:2.0.1' + implementation 'com.github.UnifiedPush:android-connector:2.1.0' implementation "androidx.emoji2:emoji2:1.2.0" From 1ff4a5f212739502b05071e10f8c77dbc8330826 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 15 Sep 2022 15:36:21 +0200 Subject: [PATCH 077/187] Ignore `AlwaysShowAction` lint issue. Also make it an error, so that developer has to explicitly disable the warning. --- library/ui-styles/src/debug/res/menu/menu_debug.xml | 5 +++-- tools/lint/lint.xml | 3 +++ .../app/features/home/room/detail/TimelineFragment.kt | 1 + vector/src/main/res/menu/menu_home.xml | 3 ++- vector/src/main/res/menu/menu_manage_space.xml | 8 +++++--- 5 files changed, 14 insertions(+), 6 deletions(-) diff --git a/library/ui-styles/src/debug/res/menu/menu_debug.xml b/library/ui-styles/src/debug/res/menu/menu_debug.xml index c58a29db8f..ac98ce8e2c 100644 --- a/library/ui-styles/src/debug/res/menu/menu_debug.xml +++ b/library/ui-styles/src/debug/res/menu/menu_debug.xml @@ -14,6 +14,7 @@ android:id="@+id/menuDebug2" android:icon="@drawable/ic_debug_icon" android:title="Send" - app:showAsAction="always" /> + app:showAsAction="always" + tools:ignore="AlwaysShowAction" /> - \ No newline at end of file + diff --git a/tools/lint/lint.xml b/tools/lint/lint.xml index 1776bd341f..84f55bb715 100644 --- a/tools/lint/lint.xml +++ b/tools/lint/lint.xml @@ -19,6 +19,9 @@ + + + diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt index 5eb90dde4b..726d1230db 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt @@ -1124,6 +1124,7 @@ class TimelineFragment : .findViewById(R.id.action_view_icon_image) .setColorFilter(colorProvider.getColorFromAttribute(R.attr.colorPrimary)) actionView.findViewById(R.id.cart_badge).setTextOrHide("$widgetsCount") + @Suppress("AlwaysShowAction") matrixAppsMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS) } diff --git a/vector/src/main/res/menu/menu_home.xml b/vector/src/main/res/menu/menu_home.xml index f15c31b4e9..a78907bd93 100644 --- a/vector/src/main/res/menu/menu_home.xml +++ b/vector/src/main/res/menu/menu_home.xml @@ -34,6 +34,7 @@ android:icon="@drawable/ic_filter" android:title="@string/home_filter_placeholder_home" app:iconTint="?vctr_content_secondary" - app:showAsAction="always" /> + app:showAsAction="always" + tools:ignore="AlwaysShowAction" /> diff --git a/vector/src/main/res/menu/menu_manage_space.xml b/vector/src/main/res/menu/menu_manage_space.xml index 86defa7869..171614ef3f 100644 --- a/vector/src/main/res/menu/menu_manage_space.xml +++ b/vector/src/main/res/menu/menu_manage_space.xml @@ -1,12 +1,14 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + app:showAsAction="always" + tools:ignore="AlwaysShowAction" /> - \ No newline at end of file + From bb2eb56ee69928cd90df43121f89b3c9713bda11 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 15 Sep 2022 15:51:27 +0200 Subject: [PATCH 078/187] Add `@ChecksSdkIntAtLeast` annotation. --- .../matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt | 3 +++ .../main/java/im/vector/app/features/home/ShortcutCreator.kt | 2 ++ .../im/vector/app/features/notifications/NotificationUtils.kt | 3 ++- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt index 900a2e237f..acbf9ca061 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.api.util +import androidx.annotation.ChecksSdkIntAtLeast + interface BuildVersionSdkIntProvider { /** * Return the current version of the Android SDK. @@ -26,6 +28,7 @@ interface BuildVersionSdkIntProvider { * Checks the if the current OS version is equal or greater than [version]. * @return A `non-null` result if true, `null` otherwise. */ + @ChecksSdkIntAtLeast(parameter = 0, lambda = 1) fun whenAtLeast(version: Int, result: () -> T): T? { return if (get() >= version) { result() diff --git a/vector/src/main/java/im/vector/app/features/home/ShortcutCreator.kt b/vector/src/main/java/im/vector/app/features/home/ShortcutCreator.kt index 861fdc64b2..e0565debf2 100644 --- a/vector/src/main/java/im/vector/app/features/home/ShortcutCreator.kt +++ b/vector/src/main/java/im/vector/app/features/home/ShortcutCreator.kt @@ -20,6 +20,7 @@ import android.content.Context import android.content.pm.ShortcutInfo import android.graphics.Bitmap import android.os.Build +import androidx.annotation.ChecksSdkIntAtLeast import androidx.annotation.WorkerThread import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutManagerCompat @@ -32,6 +33,7 @@ import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.util.toMatrixItem import javax.inject.Inject +@ChecksSdkIntAtLeast(api = Build.VERSION_CODES.O) private val useAdaptiveIcon = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O private const val adaptiveIconSizeDp = 108 private const val adaptiveIconOuterSidesDp = 18 diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index 8f05819fc4..6d1c77d9e9 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -34,6 +34,7 @@ import android.text.Spannable import android.text.SpannableString import android.text.style.ForegroundColorSpan import androidx.annotation.AttrRes +import androidx.annotation.ChecksSdkIntAtLeast import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.core.app.NotificationCompat @@ -102,6 +103,7 @@ class NotificationUtils @Inject constructor( const val SILENT_NOTIFICATION_CHANNEL_ID = "DEFAULT_SILENT_NOTIFICATION_CHANNEL_ID_V2" private const val CALL_NOTIFICATION_CHANNEL_ID = "CALL_NOTIFICATION_CHANNEL_ID_V2" + @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.O) fun supportNotificationChannels() = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) fun openSystemSettingsForSilentCategory(fragment: Fragment) { @@ -126,7 +128,6 @@ class NotificationUtils @Inject constructor( /** * Create notification channels. */ - @TargetApi(Build.VERSION_CODES.O) fun createNotificationChannels() { if (!supportNotificationChannels()) { return From 832a472b574faf1ca683034a78e453dcca2130fb Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 15:22:21 +0200 Subject: [PATCH 079/187] Add `@ChecksSdkIntAtLeast` annotation, to be able to remove `AndroidVersionTestOverrider` --- .../vector/app/AndroidVersionTestOverrider.kt | 46 ------------------- .../voice/VoiceRecorderProviderTests.kt | 17 +++---- .../features/voice/VoiceRecorderProvider.kt | 8 +++- 3 files changed, 13 insertions(+), 58 deletions(-) delete mode 100644 vector/src/androidTest/java/im/vector/app/AndroidVersionTestOverrider.kt diff --git a/vector/src/androidTest/java/im/vector/app/AndroidVersionTestOverrider.kt b/vector/src/androidTest/java/im/vector/app/AndroidVersionTestOverrider.kt deleted file mode 100644 index 97333b7c98..0000000000 --- a/vector/src/androidTest/java/im/vector/app/AndroidVersionTestOverrider.kt +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2022 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.vector.app - -import android.os.Build -import java.lang.reflect.Field - -/** - * Used to override [Build.VERSION.SDK_INT]. Ideally an interface should be used instead, but that approach forces us to either add suppress lint annotations - * and potentially miss an API version issue or write a custom lint rule, which seems like an overkill. - */ -object AndroidVersionTestOverrider { - - private var initialValue: Int? = null - - fun override(newVersion: Int) { - if (initialValue == null) { - initialValue = Build.VERSION.SDK_INT - } - val field = Build.VERSION::class.java.getField("SDK_INT") - setStaticField(field, newVersion) - } - - fun restore() { - initialValue?.let { override(it) } - } - - private fun setStaticField(field: Field, value: Any) { - field.isAccessible = true - field.set(null, value) - } -} diff --git a/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderProviderTests.kt b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderProviderTests.kt index 65f81b145b..0610496dfe 100644 --- a/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderProviderTests.kt +++ b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderProviderTests.kt @@ -18,41 +18,36 @@ package im.vector.app.features.voice import android.os.Build import androidx.test.platform.app.InstrumentationRegistry -import im.vector.app.AndroidVersionTestOverrider +import im.vector.app.TestBuildVersionSdkIntProvider import im.vector.app.features.DefaultVectorFeatures import io.mockk.every import io.mockk.spyk import org.amshove.kluent.shouldBeInstanceOf -import org.junit.After import org.junit.Test class VoiceRecorderProviderTests { private val context = InstrumentationRegistry.getInstrumentation().targetContext - private val provider = spyk(VoiceRecorderProvider(context, DefaultVectorFeatures())) - - @After - fun tearDown() { - AndroidVersionTestOverrider.restore() - } + private val buildVersionSdkIntProvider = TestBuildVersionSdkIntProvider() + private val provider = spyk(VoiceRecorderProvider(context, DefaultVectorFeatures(), buildVersionSdkIntProvider)) @Test fun provideVoiceRecorderOnAndroidQAndCodecReturnsQRecorder() { - AndroidVersionTestOverrider.override(Build.VERSION_CODES.Q) + buildVersionSdkIntProvider.value = Build.VERSION_CODES.Q every { provider.hasOpusEncoder() } returns true provider.provideVoiceRecorder().shouldBeInstanceOf(VoiceRecorderQ::class) } @Test fun provideVoiceRecorderOnAndroidQButNoCodecReturnsLRecorder() { - AndroidVersionTestOverrider.override(Build.VERSION_CODES.Q) + buildVersionSdkIntProvider.value = Build.VERSION_CODES.Q every { provider.hasOpusEncoder() } returns false provider.provideVoiceRecorder().shouldBeInstanceOf(VoiceRecorderL::class) } @Test fun provideVoiceRecorderOnOlderAndroidVersionReturnsLRecorder() { - AndroidVersionTestOverrider.override(Build.VERSION_CODES.LOLLIPOP) + buildVersionSdkIntProvider.value = Build.VERSION_CODES.LOLLIPOP provider.provideVoiceRecorder().shouldBeInstanceOf(VoiceRecorderL::class) } } diff --git a/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt b/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt index 1bf289fb4c..c024e0c6d4 100644 --- a/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt +++ b/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt @@ -20,14 +20,17 @@ import android.content.Context import android.media.MediaCodecList import android.media.MediaFormat import android.os.Build +import androidx.annotation.ChecksSdkIntAtLeast import androidx.annotation.VisibleForTesting import im.vector.app.features.VectorFeatures import kotlinx.coroutines.Dispatchers +import org.matrix.android.sdk.api.util.BuildVersionSdkIntProvider import javax.inject.Inject class VoiceRecorderProvider @Inject constructor( private val context: Context, private val vectorFeatures: VectorFeatures, + private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider, ) { fun provideVoiceRecorder(): VoiceRecorder { return if (useFallbackRecorder()) { @@ -37,8 +40,11 @@ class VoiceRecorderProvider @Inject constructor( } } + @ChecksSdkIntAtLeast(api = 29) private fun useFallbackRecorder(): Boolean { - return Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || !hasOpusEncoder() || vectorFeatures.forceUsageOfOpusEncoder() + return buildVersionSdkIntProvider.get() < Build.VERSION_CODES.Q || + !hasOpusEncoder() || + vectorFeatures.forceUsageOfOpusEncoder() } @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) From 7e8a39e6de80ff749e55b5b78cf2c6dc59b80b8e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 15 Sep 2022 16:02:28 +0200 Subject: [PATCH 080/187] Suppress `LaunchActivityFromNotification`. This is fine here, this is the notification for the diagnostic, we do not want to start an Activity. --- tools/lint/lint.xml | 3 +++ .../im/vector/app/features/notifications/NotificationUtils.kt | 1 + 2 files changed, 4 insertions(+) diff --git a/tools/lint/lint.xml b/tools/lint/lint.xml index 84f55bb715..8b4b6ef617 100644 --- a/tools/lint/lint.xml +++ b/tools/lint/lint.xml @@ -108,6 +108,9 @@ + + + diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index 6d1c77d9e9..d00c1dcc42 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -967,6 +967,7 @@ class NotificationUtils @Inject constructor( } } + @SuppressLint("LaunchActivityFromNotification") fun displayDiagnosticNotification() { val testActionIntent = Intent(context, TestNotificationReceiver::class.java) testActionIntent.action = actionIds.diagnostic From d8436874e2c2d3338c128c9234701639965ae23d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 11:41:41 +0200 Subject: [PATCH 081/187] Fix `StaticFieldLeak` issue (context). Make VectorLocal an injectable class. --- tools/lint/lint.xml | 1 + .../java/im/vector/app/VectorApplication.kt | 3 +- .../app/core/platform/VectorBaseActivity.kt | 4 ++- .../features/call/conference/JitsiService.kt | 3 +- .../call/dialpad/CallDialPadBottomSheet.kt | 7 ++++- .../features/call/dialpad/PstnDialActivity.kt | 2 +- .../call/transfer/CallTransferActivity.kt | 2 +- .../call/transfer/CallTransferPagerAdapter.kt | 5 ++-- .../configuration/VectorConfiguration.kt | 15 +++++----- .../setup/KeysBackupSetupStep2Fragment.kt | 7 +++-- .../BootstrapEnterPassphraseFragment.kt | 7 +++-- .../app/features/home/HomeDetailFragment.kt | 3 +- .../app/features/rageshake/BugReporter.kt | 3 +- .../app/features/settings/VectorLocale.kt | 29 ++++++++++--------- .../VectorSettingsPreferencesFragment.kt | 3 +- .../settings/locale/LocalePickerController.kt | 16 +++++----- .../settings/locale/LocalePickerViewModel.kt | 12 ++++++-- .../settings/locale/LocalePickerViewState.kt | 3 +- 18 files changed, 78 insertions(+), 47 deletions(-) diff --git a/tools/lint/lint.xml b/tools/lint/lint.xml index 8b4b6ef617..3d3b073749 100644 --- a/tools/lint/lint.xml +++ b/tools/lint/lint.xml @@ -80,6 +80,7 @@ + diff --git a/vector-app/src/main/java/im/vector/app/VectorApplication.kt b/vector-app/src/main/java/im/vector/app/VectorApplication.kt index ee04d908e8..5e789d9504 100644 --- a/vector-app/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector-app/src/main/java/im/vector/app/VectorApplication.kt @@ -109,6 +109,7 @@ class VectorApplication : @Inject lateinit var fcmHelper: FcmHelper @Inject lateinit var buildMeta: BuildMeta @Inject lateinit var leakDetector: LeakDetector + @Inject lateinit var vectorLocale: VectorLocale // font thread handler private var fontThreadHandler: Handler? = null @@ -159,7 +160,7 @@ class VectorApplication : R.array.com_google_android_gms_fonts_certs ) FontsContractCompat.requestFont(this, fontRequest, emojiCompatFontProvider, getFontThreadHandler()) - VectorLocale.init(this, buildMeta) + vectorLocale.init() ThemeUtils.init(this) vectorConfiguration.applyToApplicationContext() diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index b4ba384f8f..fbcfd69610 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -84,6 +84,7 @@ import im.vector.app.features.rageshake.RageShake import im.vector.app.features.session.SessionListener import im.vector.app.features.settings.FontScalePreferences import im.vector.app.features.settings.FontScalePreferencesImpl +import im.vector.app.features.settings.VectorLocale import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.themes.ActivityOtherThemes import im.vector.app.features.themes.ThemeUtils @@ -155,6 +156,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver @Inject lateinit var rageShake: RageShake @Inject lateinit var buildMeta: BuildMeta @Inject lateinit var fontScalePreferences: FontScalePreferences + @Inject lateinit var vectorLocale: VectorLocale // For debug only @Inject lateinit var debugReceiver: DebugReceiver @@ -177,7 +179,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver override fun attachBaseContext(base: Context) { val fontScalePreferences = FontScalePreferencesImpl(PreferenceManager.getDefaultSharedPreferences(base), AndroidSystemSettingsProvider(base)) - val vectorConfiguration = VectorConfiguration(this, fontScalePreferences) + val vectorConfiguration = VectorConfiguration(this, fontScalePreferences, vectorLocale) super.attachBaseContext(vectorConfiguration.getLocalisedContext(base)) } diff --git a/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt b/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt index b0da4f0e18..bdb6cfb0d0 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt @@ -49,6 +49,7 @@ class JitsiService @Inject constructor( private val themeProvider: ThemeProvider, private val jitsiJWTFactory: JitsiJWTFactory, private val clock: Clock, + private val vectorLocale: VectorLocale, ) { companion object { @@ -163,7 +164,7 @@ class JitsiService @Inject constructor( if (widgetSessionId.length > 8) { widgetSessionId = widgetSessionId.substring(0, 7) } - roomId.substring(1, roomId.indexOf(":") - 1) + widgetSessionId.lowercase(VectorLocale.applicationLocale) + roomId.substring(1, roomId.indexOf(":") - 1) + widgetSessionId.lowercase(vectorLocale.applicationLocale) } } diff --git a/vector/src/main/java/im/vector/app/features/call/dialpad/CallDialPadBottomSheet.kt b/vector/src/main/java/im/vector/app/features/call/dialpad/CallDialPadBottomSheet.kt index 8bf2ce47bd..be38f7d509 100644 --- a/vector/src/main/java/im/vector/app/features/call/dialpad/CallDialPadBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/call/dialpad/CallDialPadBottomSheet.kt @@ -20,12 +20,15 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import dagger.hilt.android.AndroidEntryPoint import im.vector.app.R import im.vector.app.core.extensions.addChildFragment import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment import im.vector.app.databinding.BottomSheetCallDialPadBinding import im.vector.app.features.settings.VectorLocale +import javax.inject.Inject +@AndroidEntryPoint class CallDialPadBottomSheet : VectorBaseBottomSheetDialogFragment() { companion object { @@ -41,6 +44,8 @@ class CallDialPadBottomSheet : VectorBaseBottomSheetDialogFragment() { } } - sectionsPagerAdapter = CallTransferPagerAdapter(this) + sectionsPagerAdapter = CallTransferPagerAdapter(this, vectorLocale) views.callTransferViewPager.adapter = sectionsPagerAdapter TabLayoutMediator(views.callTransferTabLayout, views.callTransferViewPager) { tab, position -> diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferPagerAdapter.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferPagerAdapter.kt index 3ec8f61978..f5ab172585 100644 --- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferPagerAdapter.kt +++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferPagerAdapter.kt @@ -27,7 +27,8 @@ import im.vector.app.features.userdirectory.UserListFragment import im.vector.app.features.userdirectory.UserListFragmentArgs class CallTransferPagerAdapter( - private val fragmentActivity: FragmentActivity + private val fragmentActivity: FragmentActivity, + private val vectorLocale: VectorLocale, ) : FragmentStateAdapter(fragmentActivity) { companion object { @@ -61,7 +62,7 @@ class CallTransferPagerAdapter( arguments = Bundle().apply { putBoolean(DialPadFragment.EXTRA_ENABLE_DELETE, true) putBoolean(DialPadFragment.EXTRA_ENABLE_OK, false) - putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country) + putString(DialPadFragment.EXTRA_REGION_CODE, vectorLocale.applicationLocale.country) } } } diff --git a/vector/src/main/java/im/vector/app/features/configuration/VectorConfiguration.kt b/vector/src/main/java/im/vector/app/features/configuration/VectorConfiguration.kt index a3d801e534..f67706dbd7 100644 --- a/vector/src/main/java/im/vector/app/features/configuration/VectorConfiguration.kt +++ b/vector/src/main/java/im/vector/app/features/configuration/VectorConfiguration.kt @@ -33,21 +33,22 @@ import javax.inject.Inject */ class VectorConfiguration @Inject constructor( private val context: Context, - private val fontScalePreferences: FontScalePreferences + private val fontScalePreferences: FontScalePreferences, + private val vectorLocale: VectorLocale, ) { fun onConfigurationChanged() { - if (Locale.getDefault().toString() != VectorLocale.applicationLocale.toString()) { + if (Locale.getDefault().toString() != vectorLocale.applicationLocale.toString()) { Timber.v("## onConfigurationChanged(): the locale has been updated to ${Locale.getDefault()}") - Timber.v("## onConfigurationChanged(): restore the expected value ${VectorLocale.applicationLocale}") - Locale.setDefault(VectorLocale.applicationLocale) + Timber.v("## onConfigurationChanged(): restore the expected value ${vectorLocale.applicationLocale}") + Locale.setDefault(vectorLocale.applicationLocale) } // Night mode may have changed ThemeUtils.init(context) } fun applyToApplicationContext() { - val locale = VectorLocale.applicationLocale + val locale = vectorLocale.applicationLocale val fontScale = fontScalePreferences.getResolvedFontScaleValue() Locale.setDefault(locale) @@ -67,7 +68,7 @@ class VectorConfiguration @Inject constructor( */ fun getLocalisedContext(context: Context): Context { try { - val locale = VectorLocale.applicationLocale + val locale = vectorLocale.applicationLocale // create new configuration passing old configuration from original Context val configuration = Configuration(context.resources.configuration) @@ -107,7 +108,7 @@ class VectorConfiguration @Inject constructor( * @return the local status value */ fun getHash(): String { - return (VectorLocale.applicationLocale.toString() + + return (vectorLocale.applicationLocale.toString() + "_" + fontScalePreferences.getResolvedFontScaleValue().preferenceValue + "_" + ThemeUtils.getApplicationTheme(context)) } diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt index cf92afcc2e..4ee6126fb7 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/setup/KeysBackupSetupStep2Fragment.kt @@ -32,6 +32,7 @@ import im.vector.app.databinding.FragmentKeysBackupSetupStep2Binding import im.vector.app.features.settings.VectorLocale import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import javax.inject.Inject @AndroidEntryPoint class KeysBackupSetupStep2Fragment : @@ -43,6 +44,8 @@ class KeysBackupSetupStep2Fragment : private val zxcvbn = Zxcvbn() + @Inject lateinit var vectorLocale: VectorLocale + private fun onPassphraseChanged() { viewModel.passphrase.value = views.keysBackupSetupStep2PassphraseEnterEdittext.text.toString() viewModel.confirmPassphraseError.value = null @@ -78,12 +81,12 @@ class KeysBackupSetupStep2Fragment : views.keysBackupSetupStep2PassphraseStrengthLevel.strength = score if (score in 1..3) { - val warning = strength.feedback?.getWarning(VectorLocale.applicationLocale) + val warning = strength.feedback?.getWarning(vectorLocale.applicationLocale) if (warning != null) { views.keysBackupSetupStep2PassphraseEnterTil.error = warning } - val suggestions = strength.feedback?.getSuggestions(VectorLocale.applicationLocale) + val suggestions = strength.feedback?.getSuggestions(vectorLocale.applicationLocale) if (suggestions != null) { views.keysBackupSetupStep2PassphraseEnterTil.error = suggestions.firstOrNull() } diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt index 43cc25f195..de04e59245 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapEnterPassphraseFragment.kt @@ -34,6 +34,7 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.android.widget.editorActionEvents import reactivecircus.flowbinding.android.widget.textChanges +import javax.inject.Inject @AndroidEntryPoint class BootstrapEnterPassphraseFragment : @@ -43,6 +44,8 @@ class BootstrapEnterPassphraseFragment : return FragmentBootstrapEnterPassphraseBinding.inflate(inflater, container, false) } + @Inject lateinit var vectorLocale: VectorLocale + val sharedViewModel: BootstrapSharedViewModel by parentFragmentViewModel() override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -105,8 +108,8 @@ class BootstrapEnterPassphraseFragment : views.ssssPassphraseSecurityProgress.strength = score if (score in 1..3) { val hint = - strength.feedback?.getWarning(VectorLocale.applicationLocale)?.takeIf { it.isNotBlank() } - ?: strength.feedback?.getSuggestions(VectorLocale.applicationLocale)?.firstOrNull() + strength.feedback?.getWarning(vectorLocale.applicationLocale)?.takeIf { it.isNotBlank() } + ?: strength.feedback?.getSuggestions(vectorLocale.applicationLocale)?.firstOrNull() if (hint != null && hint != views.ssssPassphraseEnterTil.error.toString()) { views.ssssPassphraseEnterTil.error = hint } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt index 8eab759fcd..e4fa267af6 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt @@ -75,6 +75,7 @@ class HomeDetailFragment : @Inject lateinit var callManager: WebRtcCallManager @Inject lateinit var vectorPreferences: VectorPreferences @Inject lateinit var spaceStateHandler: SpaceStateHandler + @Inject lateinit var vectorLocale: VectorLocale private val viewModel: HomeDetailViewModel by fragmentViewModel() private val unknownDeviceDetectorSharedViewModel: UnknownDeviceDetectorSharedViewModel by activityViewModel() @@ -378,7 +379,7 @@ class HomeDetailFragment : arguments = Bundle().apply { putBoolean(DialPadFragment.EXTRA_ENABLE_DELETE, true) putBoolean(DialPadFragment.EXTRA_ENABLE_OK, true) - putString(DialPadFragment.EXTRA_REGION_CODE, VectorLocale.applicationLocale.country) + putString(DialPadFragment.EXTRA_REGION_CODE, vectorLocale.applicationLocale.country) } applyCallback() } diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt index eefbf63a12..d22f3f9b58 100755 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt @@ -80,6 +80,7 @@ class BugReporter @Inject constructor( private val buildMeta: BuildMeta, private val processInfo: ProcessInfo, private val sdkIntProvider: BuildVersionSdkIntProvider, + private val vectorLocale: VectorLocale, ) { var inMultiWindowMode = false @@ -294,7 +295,7 @@ class BugReporter @Inject constructor( Build.VERSION.INCREMENTAL + "-" + Build.VERSION.CODENAME ) .addFormDataPart("locale", Locale.getDefault().toString()) - .addFormDataPart("app_language", VectorLocale.applicationLocale.toString()) + .addFormDataPart("app_language", vectorLocale.applicationLocale.toString()) .addFormDataPart("default_app_language", systemLocaleProvider.getSystemLocale().toString()) .addFormDataPart("theme", ThemeUtils.getApplicationTheme(context)) .addFormDataPart("server_version", serverVersion) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt index 4666d586d3..438434ed3c 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt @@ -27,19 +27,27 @@ import kotlinx.coroutines.withContext import timber.log.Timber import java.util.IllformedLocaleException import java.util.Locale +import javax.inject.Inject +import javax.inject.Singleton /** * Object to manage the Locale choice of the user. */ -object VectorLocale { - private const val APPLICATION_LOCALE_COUNTRY_KEY = "APPLICATION_LOCALE_COUNTRY_KEY" - private const val APPLICATION_LOCALE_VARIANT_KEY = "APPLICATION_LOCALE_VARIANT_KEY" - private const val APPLICATION_LOCALE_LANGUAGE_KEY = "APPLICATION_LOCALE_LANGUAGE_KEY" - private const val APPLICATION_LOCALE_SCRIPT_KEY = "APPLICATION_LOCALE_SCRIPT_KEY" +@Singleton +class VectorLocale @Inject constructor( + private val context: Context, + private val buildMeta: BuildMeta, +) { + companion object { + private const val APPLICATION_LOCALE_COUNTRY_KEY = "APPLICATION_LOCALE_COUNTRY_KEY" + private const val APPLICATION_LOCALE_VARIANT_KEY = "APPLICATION_LOCALE_VARIANT_KEY" + private const val APPLICATION_LOCALE_LANGUAGE_KEY = "APPLICATION_LOCALE_LANGUAGE_KEY" + private const val APPLICATION_LOCALE_SCRIPT_KEY = "APPLICATION_LOCALE_SCRIPT_KEY" + private const val ISO_15924_LATN = "Latn" + } private val defaultLocale = Locale("en", "US") - private const val ISO_15924_LATN = "Latn" /** * The cache of supported application languages. @@ -52,15 +60,10 @@ object VectorLocale { var applicationLocale = defaultLocale private set - private lateinit var context: Context - private lateinit var buildMeta: BuildMeta - /** - * Init this object. + * Init this singleton. */ - fun init(context: Context, buildMeta: BuildMeta) { - this.context = context - this.buildMeta = buildMeta + fun init() { val preferences = DefaultSharedPreferences.getInstance(context) if (preferences.contains(APPLICATION_LOCALE_LANGUAGE_KEY)) { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt index 3c8ec56713..073d5f7468 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsPreferencesFragment.kt @@ -46,6 +46,7 @@ class VectorSettingsPreferencesFragment : @Inject lateinit var vectorPreferences: VectorPreferences @Inject lateinit var fontScalePreferences: FontScalePreferences @Inject lateinit var vectorFeatures: VectorFeatures + @Inject lateinit var vectorLocale: VectorLocale override var titleRes = R.string.settings_preferences override val preferenceXmlRes = R.xml.vector_settings_preferences @@ -198,7 +199,7 @@ class VectorSettingsPreferencesFragment : private fun setUserInterfacePreferences() { // Selected language - selectedLanguagePreference.summary = VectorLocale.localeToLocalisedString(VectorLocale.applicationLocale) + selectedLanguagePreference.summary = vectorLocale.localeToLocalisedString(vectorLocale.applicationLocale) // Text size textSizePreference.summary = getString(fontScalePreferences.getResolvedFontScaleValue().nameResId) diff --git a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerController.kt b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerController.kt index 9853b28aae..0cbfef7495 100644 --- a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerController.kt +++ b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerController.kt @@ -37,13 +37,15 @@ import javax.inject.Inject class LocalePickerController @Inject constructor( private val vectorPreferences: VectorPreferences, private val stringProvider: StringProvider, - private val errorFormatter: ErrorFormatter + private val errorFormatter: ErrorFormatter, + private val vectorLocale: VectorLocale, ) : TypedEpoxyController() { var listener: Listener? = null override fun buildModels(data: LocalePickerViewState?) { val list = data?.locales ?: return + val currentLocale = data.currentLocale ?: return val host = this profileSectionItem { @@ -51,10 +53,10 @@ class LocalePickerController @Inject constructor( title(host.stringProvider.getString(R.string.choose_locale_current_locale_title)) } localeItem { - id(data.currentLocale.toString()) - title(VectorLocale.localeToLocalisedString(data.currentLocale).safeCapitalize(data.currentLocale)) + id(currentLocale.toString()) + title(host.vectorLocale.localeToLocalisedString(currentLocale).safeCapitalize(currentLocale)) if (host.vectorPreferences.developerMode()) { - subtitle(VectorLocale.localeToLocalisedStringInfo(data.currentLocale)) + subtitle(host.vectorLocale.localeToLocalisedStringInfo(currentLocale)) } clickListener { host.listener?.onUseCurrentClicked() } } @@ -78,13 +80,13 @@ class LocalePickerController @Inject constructor( } } else { list() - .filter { it.toString() != data.currentLocale.toString() } + .filter { it.toString() != currentLocale.toString() } .forEach { locale -> localeItem { id(locale.toString()) - title(VectorLocale.localeToLocalisedString(locale).safeCapitalize(locale)) + title(host.vectorLocale.localeToLocalisedString(locale).safeCapitalize(locale)) if (host.vectorPreferences.developerMode()) { - subtitle(VectorLocale.localeToLocalisedStringInfo(locale)) + subtitle(host.vectorLocale.localeToLocalisedStringInfo(locale)) } clickListener { host.listener?.onLocaleClicked(locale) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt index 0bbbc323e0..c38f9b5b87 100644 --- a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewModel.kt @@ -30,7 +30,8 @@ import kotlinx.coroutines.launch class LocalePickerViewModel @AssistedInject constructor( @Assisted initialState: LocalePickerViewState, - private val vectorConfiguration: VectorConfiguration + private val vectorConfiguration: VectorConfiguration, + private val vectorLocale: VectorLocale, ) : VectorViewModel(initialState) { @AssistedFactory @@ -39,8 +40,13 @@ class LocalePickerViewModel @AssistedInject constructor( } init { + setState { + copy( + currentLocale = vectorLocale.applicationLocale + ) + } viewModelScope.launch { - val result = VectorLocale.getSupportedLocales() + val result = vectorLocale.getSupportedLocales() setState { copy( @@ -59,7 +65,7 @@ class LocalePickerViewModel @AssistedInject constructor( } private fun handleSelectLocale(action: LocalePickerAction.SelectLocale) { - VectorLocale.saveApplicationLocale(action.locale) + vectorLocale.saveApplicationLocale(action.locale) vectorConfiguration.applyToApplicationContext() _viewEvents.post(LocalePickerViewEvents.RestartActivity) } diff --git a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewState.kt b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewState.kt index 8cb5978393..f981e7a444 100644 --- a/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewState.kt +++ b/vector/src/main/java/im/vector/app/features/settings/locale/LocalePickerViewState.kt @@ -19,10 +19,9 @@ package im.vector.app.features.settings.locale import com.airbnb.mvrx.Async import com.airbnb.mvrx.MavericksState import com.airbnb.mvrx.Uninitialized -import im.vector.app.features.settings.VectorLocale import java.util.Locale data class LocalePickerViewState( - val currentLocale: Locale = VectorLocale.applicationLocale, + val currentLocale: Locale? = null, val locales: Async> = Uninitialized ) : MavericksState From 0324927b04d384797f2e03df5acb1edbba922f8d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 15:20:23 +0200 Subject: [PATCH 082/187] Create VectorLocaleProvider, to just read the current Locale from the SharedPreference --- .../app/core/platform/VectorBaseActivity.kt | 10 +++-- .../features/call/conference/JitsiService.kt | 4 +- .../call/dialpad/CallDialPadBottomSheet.kt | 4 +- .../features/call/dialpad/PstnDialActivity.kt | 1 - .../call/transfer/CallTransferPagerAdapter.kt | 4 +- .../configuration/VectorConfiguration.kt | 4 +- .../setup/KeysBackupSetupStep2Fragment.kt | 4 +- .../BootstrapEnterPassphraseFragment.kt | 4 +- .../app/features/home/HomeDetailFragment.kt | 4 +- .../notifications/NotificationUtils.kt | 1 - .../app/features/rageshake/BugReporter.kt | 4 +- .../app/features/settings/VectorLocale.kt | 7 ++-- .../features/settings/VectorLocaleProvider.kt | 41 +++++++++++++++++++ 13 files changed, 66 insertions(+), 26 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/VectorLocaleProvider.kt diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index fbcfd69610..0b8d6698d2 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -84,7 +84,7 @@ import im.vector.app.features.rageshake.RageShake import im.vector.app.features.session.SessionListener import im.vector.app.features.settings.FontScalePreferences import im.vector.app.features.settings.FontScalePreferencesImpl -import im.vector.app.features.settings.VectorLocale +import im.vector.app.features.settings.VectorLocaleProvider import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.themes.ActivityOtherThemes import im.vector.app.features.themes.ThemeUtils @@ -156,7 +156,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver @Inject lateinit var rageShake: RageShake @Inject lateinit var buildMeta: BuildMeta @Inject lateinit var fontScalePreferences: FontScalePreferences - @Inject lateinit var vectorLocale: VectorLocale + @Inject lateinit var vectorLocale: VectorLocaleProvider // For debug only @Inject lateinit var debugReceiver: DebugReceiver @@ -178,8 +178,10 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver private val restorables = ArrayList() override fun attachBaseContext(base: Context) { - val fontScalePreferences = FontScalePreferencesImpl(PreferenceManager.getDefaultSharedPreferences(base), AndroidSystemSettingsProvider(base)) - val vectorConfiguration = VectorConfiguration(this, fontScalePreferences, vectorLocale) + val preferences = PreferenceManager.getDefaultSharedPreferences(base) + val fontScalePreferences = FontScalePreferencesImpl(preferences, AndroidSystemSettingsProvider(base)) + val vectorLocaleProvider = VectorLocaleProvider(preferences) + val vectorConfiguration = VectorConfiguration(this, fontScalePreferences, vectorLocaleProvider) super.attachBaseContext(vectorConfiguration.getLocalisedContext(base)) } diff --git a/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt b/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt index bdb6cfb0d0..d14f358801 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/JitsiService.kt @@ -25,7 +25,7 @@ import im.vector.app.core.utils.toBase32String import im.vector.app.features.call.conference.jwt.JitsiJWTFactory import im.vector.app.features.displayname.getBestName import im.vector.app.features.raw.wellknown.getElementWellknown -import im.vector.app.features.settings.VectorLocale +import im.vector.app.features.settings.VectorLocaleProvider import im.vector.app.features.themes.ThemeProvider import okhttp3.Request import org.jitsi.meet.sdk.JitsiMeetUserInfo @@ -49,7 +49,7 @@ class JitsiService @Inject constructor( private val themeProvider: ThemeProvider, private val jitsiJWTFactory: JitsiJWTFactory, private val clock: Clock, - private val vectorLocale: VectorLocale, + private val vectorLocale: VectorLocaleProvider, ) { companion object { diff --git a/vector/src/main/java/im/vector/app/features/call/dialpad/CallDialPadBottomSheet.kt b/vector/src/main/java/im/vector/app/features/call/dialpad/CallDialPadBottomSheet.kt index be38f7d509..c157ee42b8 100644 --- a/vector/src/main/java/im/vector/app/features/call/dialpad/CallDialPadBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/call/dialpad/CallDialPadBottomSheet.kt @@ -25,7 +25,7 @@ import im.vector.app.R import im.vector.app.core.extensions.addChildFragment import im.vector.app.core.platform.VectorBaseBottomSheetDialogFragment import im.vector.app.databinding.BottomSheetCallDialPadBinding -import im.vector.app.features.settings.VectorLocale +import im.vector.app.features.settings.VectorLocaleProvider import javax.inject.Inject @AndroidEntryPoint @@ -44,7 +44,7 @@ class CallDialPadBottomSheet : VectorBaseBottomSheetDialogFragment Date: Fri, 16 Sep 2022 16:06:49 +0200 Subject: [PATCH 083/187] Remove `DefaultSharedPreferences` since we now have @DefaultPreferences which provide a singleton. Some fun has been moved to injectable classes due to this change. Not compiling, still work to do, but I prefer to split into 2 separate commits. --- .../java/im/vector/app/VectorApplication.kt | 5 +- .../app/core/di/DefaultSharedPreferences.kt | 31 ---- .../app/core/pushers/UnifiedPushStore.kt | 9 +- .../app/core/ui/views/KeysBackupBanner.kt | 1 - .../im/vector/app/core/utils/RingtoneUtils.kt | 166 +++++++++--------- .../features/disclaimer/DisclaimerDialog.kt | 50 +++--- .../vector/app/features/home/HomeActivity.kt | 5 +- .../homeserver/ServerUrlsRepository.kt | 48 ++--- .../VectorUncaughtExceptionHandler.kt | 11 +- .../app/features/settings/VectorLocale.kt | 9 +- .../features/settings/VectorPreferences.kt | 16 +- .../VectorSettingsVoiceVideoFragment.kt | 23 +-- .../vector/app/features/themes/ThemeUtils.kt | 4 +- 13 files changed, 183 insertions(+), 195 deletions(-) delete mode 100644 vector/src/main/java/im/vector/app/core/di/DefaultSharedPreferences.kt diff --git a/vector-app/src/main/java/im/vector/app/VectorApplication.kt b/vector-app/src/main/java/im/vector/app/VectorApplication.kt index 5e789d9504..ec0a6cb2a4 100644 --- a/vector-app/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector-app/src/main/java/im/vector/app/VectorApplication.kt @@ -53,7 +53,7 @@ import im.vector.app.core.resources.BuildMeta import im.vector.app.features.analytics.VectorAnalytics import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.configuration.VectorConfiguration -import im.vector.app.features.disclaimer.doNotShowDisclaimerDialog +import im.vector.app.features.disclaimer.DisclaimerDialog import im.vector.app.features.invite.InvitesAcceptor import im.vector.app.features.lifecycle.VectorActivityLifecycleCallbacks import im.vector.app.features.notifications.NotificationDrawerManager @@ -110,6 +110,7 @@ class VectorApplication : @Inject lateinit var buildMeta: BuildMeta @Inject lateinit var leakDetector: LeakDetector @Inject lateinit var vectorLocale: VectorLocale + @Inject lateinit var disclaimerDialog: DisclaimerDialog // font thread handler private var fontThreadHandler: Handler? = null @@ -172,7 +173,7 @@ class VectorApplication : val sessionImported = legacySessionImporter.process() if (!sessionImported) { // Do not display the name change popup - doNotShowDisclaimerDialog(this) + disclaimerDialog.doNotShowDisclaimerDialog() } ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver { diff --git a/vector/src/main/java/im/vector/app/core/di/DefaultSharedPreferences.kt b/vector/src/main/java/im/vector/app/core/di/DefaultSharedPreferences.kt deleted file mode 100644 index abee0cb2e7..0000000000 --- a/vector/src/main/java/im/vector/app/core/di/DefaultSharedPreferences.kt +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2020 New Vector Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package im.vector.app.core.di - -import android.content.Context -import android.content.SharedPreferences -import androidx.preference.PreferenceManager - -object DefaultSharedPreferences { - - @Volatile private var INSTANCE: SharedPreferences? = null - - fun getInstance(context: Context): SharedPreferences = - INSTANCE ?: synchronized(this) { - INSTANCE ?: PreferenceManager.getDefaultSharedPreferences(context.applicationContext).also { INSTANCE = it } - } -} diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt index d9c6bf3159..0bdfbe8e22 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt @@ -17,16 +17,17 @@ package im.vector.app.core.pushers import android.content.Context +import android.content.SharedPreferences import androidx.core.content.edit -import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.di.DefaultPreferences import javax.inject.Inject class UnifiedPushStore @Inject constructor( val context: Context, - val fcmHelper: FcmHelper + val fcmHelper: FcmHelper, + @DefaultPreferences + private val defaultPrefs: SharedPreferences, ) { - private val defaultPrefs = DefaultSharedPreferences.getInstance(context) - /** * Retrieves the UnifiedPush Endpoint. * diff --git a/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt b/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt index e789585b63..a753139c66 100755 --- a/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt @@ -23,7 +23,6 @@ import androidx.constraintlayout.widget.ConstraintLayout import androidx.core.content.edit import androidx.core.view.isVisible import im.vector.app.R -import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.databinding.ViewKeysBackupBannerBinding import timber.log.Timber diff --git a/vector/src/main/java/im/vector/app/core/utils/RingtoneUtils.kt b/vector/src/main/java/im/vector/app/core/utils/RingtoneUtils.kt index bbed2f6000..915d840637 100644 --- a/vector/src/main/java/im/vector/app/core/utils/RingtoneUtils.kt +++ b/vector/src/main/java/im/vector/app/core/utils/RingtoneUtils.kt @@ -17,103 +17,109 @@ package im.vector.app.core.utils import android.content.Context +import android.content.SharedPreferences import android.media.Ringtone import android.media.RingtoneManager import android.net.Uri import androidx.core.content.edit -import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.di.DefaultPreferences import im.vector.app.features.settings.VectorPreferences +import javax.inject.Inject /** - * This file manages the sound ringtone for calls. - * It allows you to use the default Riot Ringtone, or the standard ringtone or set a different one from the available choices + * This class manages the sound ringtone for calls. + * It allows you to use the default Element Ringtone, or the standard ringtone or set a different one from the available choices * in Android. */ +class RingtoneUtils @Inject constructor( + @DefaultPreferences + private val sharedPreferences: SharedPreferences, + private val context: Context, +) { + /** + * Returns a Uri object that points to a specific Ringtone. + * + * If no Ringtone was explicitly set using Riot, it will return the Uri for the current system + * ringtone for calls. + * + * @return the [Uri] of the currently set [Ringtone] + * @see Ringtone + */ + fun getCallRingtoneUri(): Uri? { + val callRingtone: String? = sharedPreferences + .getString(VectorPreferences.SETTINGS_CALL_RINGTONE_URI_PREFERENCE_KEY, null) -/** - * Returns a Uri object that points to a specific Ringtone. - * - * If no Ringtone was explicitly set using Riot, it will return the Uri for the current system - * ringtone for calls. - * - * @return the [Uri] of the currently set [Ringtone] - * @see Ringtone - */ -fun getCallRingtoneUri(context: Context): Uri? { - val callRingtone: String? = DefaultSharedPreferences.getInstance(context) - .getString(VectorPreferences.SETTINGS_CALL_RINGTONE_URI_PREFERENCE_KEY, null) + callRingtone?.let { + return Uri.parse(it) + } - callRingtone?.let { - return Uri.parse(it) + return try { + // Use current system notification sound for incoming calls per default (note that it can return null) + RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE) + } catch (e: SecurityException) { + // Ignore for now + null + } } - return try { - // Use current system notification sound for incoming calls per default (note that it can return null) - RingtoneManager.getActualDefaultRingtoneUri(context, RingtoneManager.TYPE_RINGTONE) - } catch (e: SecurityException) { - // Ignore for now - null - } -} + /** + * Returns a Ringtone object that can then be played. + * + * If no Ringtone was explicitly set using Riot, it will return the current system ringtone + * for calls. + * + * @return the currently set [Ringtone] + * @see Ringtone + */ + fun getCallRingtone(): Ringtone? { + getCallRingtoneUri()?.let { + // Note that it can also return null + return RingtoneManager.getRingtone(context, it) + } -/** - * Returns a Ringtone object that can then be played. - * - * If no Ringtone was explicitly set using Riot, it will return the current system ringtone - * for calls. - * - * @return the currently set [Ringtone] - * @see Ringtone - */ -fun getCallRingtone(context: Context): Ringtone? { - getCallRingtoneUri(context)?.let { - // Note that it can also return null - return RingtoneManager.getRingtone(context, it) + return null } - return null -} + /** + * Returns a String with the name of the current Ringtone. + * + * If no Ringtone was explicitly set using Riot, it will return the name of the current system + * ringtone for calls. + * + * @return the name of the currently set [Ringtone], or null + * @see Ringtone + */ + fun getCallRingtoneName(): String? { + return getCallRingtone()?.getTitle(context) + } -/** - * Returns a String with the name of the current Ringtone. - * - * If no Ringtone was explicitly set using Riot, it will return the name of the current system - * ringtone for calls. - * - * @return the name of the currently set [Ringtone], or null - * @see Ringtone - */ -fun getCallRingtoneName(context: Context): String? { - return getCallRingtone(context)?.getTitle(context) -} + /** + * Sets the selected ringtone for riot calls. + * + * @param ringtoneUri + * @see Ringtone + */ + fun setCallRingtoneUri(ringtoneUri: Uri) { + sharedPreferences + .edit { + putString(VectorPreferences.SETTINGS_CALL_RINGTONE_URI_PREFERENCE_KEY, ringtoneUri.toString()) + } + } -/** - * Sets the selected ringtone for riot calls. - * - * @param context Android context - * @param ringtoneUri - * @see Ringtone - */ -fun setCallRingtoneUri(context: Context, ringtoneUri: Uri) { - DefaultSharedPreferences.getInstance(context) - .edit { - putString(VectorPreferences.SETTINGS_CALL_RINGTONE_URI_PREFERENCE_KEY, ringtoneUri.toString()) - } -} + /** + * Set using Riot default ringtone. + */ + fun useRiotDefaultRingtone(): Boolean { + return sharedPreferences.getBoolean(VectorPreferences.SETTINGS_CALL_RINGTONE_USE_RIOT_PREFERENCE_KEY, true) + } -/** - * Set using Riot default ringtone. - */ -fun useRiotDefaultRingtone(context: Context): Boolean { - return DefaultSharedPreferences.getInstance(context).getBoolean(VectorPreferences.SETTINGS_CALL_RINGTONE_USE_RIOT_PREFERENCE_KEY, true) -} - -/** - * Ask if default Riot ringtone has to be used. - */ -fun setUseRiotDefaultRingtone(context: Context, useRiotDefault: Boolean) { - DefaultSharedPreferences.getInstance(context) - .edit { - putBoolean(VectorPreferences.SETTINGS_CALL_RINGTONE_USE_RIOT_PREFERENCE_KEY, useRiotDefault) - } + /** + * Ask if default Riot ringtone has to be used. + */ + fun setUseRiotDefaultRingtone(useRiotDefault: Boolean) { + sharedPreferences + .edit { + putBoolean(VectorPreferences.SETTINGS_CALL_RINGTONE_USE_RIOT_PREFERENCE_KEY, useRiotDefault) + } + } } diff --git a/vector/src/main/java/im/vector/app/features/disclaimer/DisclaimerDialog.kt b/vector/src/main/java/im/vector/app/features/disclaimer/DisclaimerDialog.kt index 1c6afb30b2..8214ab7120 100644 --- a/vector/src/main/java/im/vector/app/features/disclaimer/DisclaimerDialog.kt +++ b/vector/src/main/java/im/vector/app/features/disclaimer/DisclaimerDialog.kt @@ -17,44 +17,46 @@ package im.vector.app.features.disclaimer import android.app.Activity -import android.content.Context +import android.content.SharedPreferences import androidx.core.content.edit import com.google.android.material.dialog.MaterialAlertDialogBuilder import im.vector.app.R -import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.di.DefaultPreferences import im.vector.app.core.utils.openUrlInChromeCustomTab import im.vector.app.features.settings.VectorSettingsUrls +import javax.inject.Inject // Increase this value to show again the disclaimer dialog after an upgrade of the application private const val CURRENT_DISCLAIMER_VALUE = 2 const val SHARED_PREF_KEY = "LAST_DISCLAIMER_VERSION_VALUE" -fun showDisclaimerDialog(activity: Activity) { - val sharedPrefs = DefaultSharedPreferences.getInstance(activity) +class DisclaimerDialog @Inject constructor( + @DefaultPreferences + private val sharedPrefs: SharedPreferences, +) { + fun showDisclaimerDialog(activity: Activity) { + if (sharedPrefs.getInt(SHARED_PREF_KEY, 0) < CURRENT_DISCLAIMER_VALUE) { + sharedPrefs.edit { + putInt(SHARED_PREF_KEY, CURRENT_DISCLAIMER_VALUE) + } - if (sharedPrefs.getInt(SHARED_PREF_KEY, 0) < CURRENT_DISCLAIMER_VALUE) { + val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_disclaimer_content, null) + + MaterialAlertDialogBuilder(activity) + .setView(dialogLayout) + .setCancelable(false) + .setNegativeButton(R.string.disclaimer_negative_button, null) + .setPositiveButton(R.string.disclaimer_positive_button) { _, _ -> + openUrlInChromeCustomTab(activity, null, VectorSettingsUrls.DISCLAIMER_URL) + } + .show() + } + } + + fun doNotShowDisclaimerDialog() { sharedPrefs.edit { putInt(SHARED_PREF_KEY, CURRENT_DISCLAIMER_VALUE) } - - val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_disclaimer_content, null) - - MaterialAlertDialogBuilder(activity) - .setView(dialogLayout) - .setCancelable(false) - .setNegativeButton(R.string.disclaimer_negative_button, null) - .setPositiveButton(R.string.disclaimer_positive_button) { _, _ -> - openUrlInChromeCustomTab(activity, null, VectorSettingsUrls.DISCLAIMER_URL) - } - .show() - } -} - -fun doNotShowDisclaimerDialog(context: Context) { - val sharedPrefs = DefaultSharedPreferences.getInstance(context) - - sharedPrefs.edit { - putInt(SHARED_PREF_KEY, CURRENT_DISCLAIMER_VALUE) } } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 8fb73d6571..10e8447a2b 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -56,7 +56,7 @@ import im.vector.app.features.analytics.accountdata.AnalyticsAccountDataViewMode import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.analytics.plan.ViewRoom import im.vector.app.features.crypto.recover.SetupMode -import im.vector.app.features.disclaimer.showDisclaimerDialog +import im.vector.app.features.disclaimer.DisclaimerDialog import im.vector.app.features.home.room.list.actions.RoomListSharedAction import im.vector.app.features.home.room.list.actions.RoomListSharedActionViewModel import im.vector.app.features.home.room.list.home.layout.HomeLayoutSettingBottomDialogFragment @@ -141,6 +141,7 @@ class HomeActivity : @Inject lateinit var unifiedPushHelper: UnifiedPushHelper @Inject lateinit var fcmHelper: FcmHelper @Inject lateinit var nightlyProxy: NightlyProxy + @Inject lateinit var disclaimerDialog: DisclaimerDialog private var isNewAppLayoutEnabled: Boolean = false // delete once old app layout is removed @@ -570,7 +571,7 @@ class HomeActivity : .setNegativeButton(R.string.no) { _, _ -> bugReporter.deleteCrashFile() } .show() } else { - showDisclaimerDialog(this) + disclaimerDialog.showDisclaimerDialog(this) } // Force remote backup state update to update the banner if needed diff --git a/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt b/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt index 4eca377e28..95e2aeedd1 100644 --- a/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt +++ b/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt @@ -17,28 +17,36 @@ package im.vector.app.features.homeserver import android.content.Context +import android.content.SharedPreferences import androidx.core.content.edit import im.vector.app.R -import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.di.DefaultPreferences +import im.vector.app.core.resources.StringProvider +import javax.inject.Inject /** * Object to store and retrieve home and identity server urls. */ -object ServerUrlsRepository { +class ServerUrlsRepository @Inject constructor( + @DefaultPreferences + private val sharedPreferences: SharedPreferences, + private val stringProvider: StringProvider, +) { + companion object { + // Keys used to store default servers urls from the referrer + private const val DEFAULT_REFERRER_HOME_SERVER_URL_PREF = "default_referrer_home_server_url" + private const val DEFAULT_REFERRER_IDENTITY_SERVER_URL_PREF = "default_referrer_identity_server_url" - // Keys used to store default servers urls from the referrer - private const val DEFAULT_REFERRER_HOME_SERVER_URL_PREF = "default_referrer_home_server_url" - private const val DEFAULT_REFERRER_IDENTITY_SERVER_URL_PREF = "default_referrer_identity_server_url" - - // Keys used to store current homeserver url and identity url - const val HOME_SERVER_URL_PREF = "home_server_url" - const val IDENTITY_SERVER_URL_PREF = "identity_server_url" + // Keys used to store current homeserver url and identity url + const val HOME_SERVER_URL_PREF = "home_server_url" + const val IDENTITY_SERVER_URL_PREF = "identity_server_url" + } /** * Save home and identity sever urls received by the Referrer receiver. */ - fun setDefaultUrlsFromReferrer(context: Context, homeServerUrl: String, identityServerUrl: String) { - DefaultSharedPreferences.getInstance(context) + fun setDefaultUrlsFromReferrer(homeServerUrl: String, identityServerUrl: String) { + sharedPreferences .edit { if (homeServerUrl.isNotEmpty()) { putString(DEFAULT_REFERRER_HOME_SERVER_URL_PREF, homeServerUrl) @@ -53,8 +61,8 @@ object ServerUrlsRepository { /** * Save home and identity sever urls entered by the user. May be custom or default value. */ - fun saveServerUrls(context: Context, homeServerUrl: String, identityServerUrl: String) { - DefaultSharedPreferences.getInstance(context) + fun saveServerUrls(homeServerUrl: String, identityServerUrl: String) { + sharedPreferences .edit { putString(HOME_SERVER_URL_PREF, homeServerUrl) putString(IDENTITY_SERVER_URL_PREF, identityServerUrl) @@ -64,14 +72,12 @@ object ServerUrlsRepository { /** * Return last used homeserver url, or the default one from referrer or the default one from resources. */ - fun getLastHomeServerUrl(context: Context): String { - val prefs = DefaultSharedPreferences.getInstance(context) - - return prefs.getString( + fun getLastHomeServerUrl(): String { + return sharedPreferences.getString( HOME_SERVER_URL_PREF, - prefs.getString( + sharedPreferences.getString( DEFAULT_REFERRER_HOME_SERVER_URL_PREF, - getDefaultHomeServerUrl(context) + getDefaultHomeServerUrl() )!! )!! } @@ -79,10 +85,10 @@ object ServerUrlsRepository { /** * Return true if url is the default homeserver url form resources. */ - fun isDefaultHomeServerUrl(context: Context, url: String) = url == getDefaultHomeServerUrl(context) + fun isDefaultHomeServerUrl(context: Context, url: String) = url == getDefaultHomeServerUrl() /** * Return default homeserver url from resources. */ - fun getDefaultHomeServerUrl(context: Context): String = context.getString(R.string.matrix_org_server_url) + fun getDefaultHomeServerUrl() = stringProvider.getString(R.string.matrix_org_server_url) } diff --git a/vector/src/main/java/im/vector/app/features/rageshake/VectorUncaughtExceptionHandler.kt b/vector/src/main/java/im/vector/app/features/rageshake/VectorUncaughtExceptionHandler.kt index 5496ff4a94..23b4fe04a8 100644 --- a/vector/src/main/java/im/vector/app/features/rageshake/VectorUncaughtExceptionHandler.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/VectorUncaughtExceptionHandler.kt @@ -16,10 +16,10 @@ package im.vector.app.features.rageshake -import android.content.Context +import android.content.SharedPreferences import android.os.Build import androidx.core.content.edit -import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.di.DefaultPreferences import im.vector.app.core.resources.VersionCodeProvider import im.vector.app.features.version.VersionProvider import org.matrix.android.sdk.api.Matrix @@ -31,10 +31,11 @@ import javax.inject.Singleton @Singleton class VectorUncaughtExceptionHandler @Inject constructor( - context: Context, + @DefaultPreferences + private val preferences: SharedPreferences, private val bugReporter: BugReporter, private val versionProvider: VersionProvider, - private val versionCodeProvider: VersionCodeProvider + private val versionCodeProvider: VersionCodeProvider, ) : Thread.UncaughtExceptionHandler { // key to save the crash status @@ -44,8 +45,6 @@ class VectorUncaughtExceptionHandler @Inject constructor( private var previousHandler: Thread.UncaughtExceptionHandler? = null - private val preferences = DefaultSharedPreferences.getInstance(context) - /** * Activate this handler. */ diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt index b7caac11c3..b1a3fa9566 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorLocale.kt @@ -17,10 +17,11 @@ package im.vector.app.features.settings import android.content.Context +import android.content.SharedPreferences import android.content.res.Configuration import androidx.core.content.edit import im.vector.app.R -import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.di.DefaultPreferences import im.vector.app.core.resources.BuildMeta import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext @@ -37,6 +38,8 @@ import javax.inject.Singleton class VectorLocale @Inject constructor( private val context: Context, private val buildMeta: BuildMeta, + @DefaultPreferences + private val preferences: SharedPreferences, ) { companion object { const val APPLICATION_LOCALE_COUNTRY_KEY = "APPLICATION_LOCALE_COUNTRY_KEY" @@ -63,8 +66,6 @@ class VectorLocale @Inject constructor( * Init this singleton. */ fun init() { - val preferences = DefaultSharedPreferences.getInstance(context) - if (preferences.contains(APPLICATION_LOCALE_LANGUAGE_KEY)) { applicationLocale = Locale( preferences.getString(APPLICATION_LOCALE_LANGUAGE_KEY, "")!!, @@ -90,7 +91,7 @@ class VectorLocale @Inject constructor( fun saveApplicationLocale(locale: Locale) { applicationLocale = locale - DefaultSharedPreferences.getInstance(context).edit { + preferences.edit { val language = locale.language if (language.isEmpty()) { remove(APPLICATION_LOCALE_LANGUAGE_KEY) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 4da6455f74..16d3210b45 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -24,8 +24,9 @@ import androidx.annotation.BoolRes import androidx.core.content.edit import com.squareup.seismic.ShakeDetector import im.vector.app.R -import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.di.DefaultPreferences import im.vector.app.core.resources.BuildMeta +import im.vector.app.core.resources.StringProvider import im.vector.app.core.time.Clock import im.vector.app.features.VectorFeatures import im.vector.app.features.disclaimer.SHARED_PREF_KEY @@ -41,6 +42,9 @@ class VectorPreferences @Inject constructor( private val clock: Clock, private val buildMeta: BuildMeta, private val vectorFeatures: VectorFeatures, + @DefaultPreferences + private val defaultPrefs: SharedPreferences, + private val stringProvider: StringProvider, ) { companion object { @@ -289,8 +293,6 @@ class VectorPreferences @Inject constructor( ) } - private val defaultPrefs = DefaultSharedPreferences.getInstance(context) - /** * Allow subscribing and unsubscribing to configuration changes. This is * particularly useful when you need to be notified of a configuration change @@ -716,10 +718,10 @@ class VectorPreferences @Inject constructor( */ fun getSelectedMediasSavingPeriodString(): String { return when (getSelectedMediasSavingPeriod()) { - MEDIA_SAVING_3_DAYS -> context.getString(R.string.media_saving_period_3_days) - MEDIA_SAVING_1_WEEK -> context.getString(R.string.media_saving_period_1_week) - MEDIA_SAVING_1_MONTH -> context.getString(R.string.media_saving_period_1_month) - MEDIA_SAVING_FOREVER -> context.getString(R.string.media_saving_period_forever) + MEDIA_SAVING_3_DAYS -> stringProvider.getString(R.string.media_saving_period_3_days) + MEDIA_SAVING_1_WEEK -> stringProvider.getString(R.string.media_saving_period_1_week) + MEDIA_SAVING_1_MONTH -> stringProvider.getString(R.string.media_saving_period_1_month) + MEDIA_SAVING_FOREVER -> stringProvider.getString(R.string.media_saving_period_forever) else -> "?" } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsVoiceVideoFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsVoiceVideoFragment.kt index fbf54479fc..28e167779d 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsVoiceVideoFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsVoiceVideoFragment.kt @@ -23,17 +23,19 @@ import android.net.Uri import android.os.Bundle import androidx.preference.Preference import androidx.preference.SwitchPreference +import dagger.hilt.android.AndroidEntryPoint import im.vector.app.R import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.preference.VectorPreference -import im.vector.app.core.utils.getCallRingtoneName -import im.vector.app.core.utils.getCallRingtoneUri -import im.vector.app.core.utils.setCallRingtoneUri -import im.vector.app.core.utils.setUseRiotDefaultRingtone +import im.vector.app.core.utils.RingtoneUtils import im.vector.app.features.analytics.plan.MobileScreen +import javax.inject.Inject +@AndroidEntryPoint class VectorSettingsVoiceVideoFragment : VectorSettingsBaseFragment() { + @Inject lateinit var ringtoneUtils: RingtoneUtils + override var titleRes = R.string.preference_voice_and_video override val preferenceXmlRes = R.xml.vector_settings_voice_video @@ -52,12 +54,12 @@ class VectorSettingsVoiceVideoFragment : VectorSettingsBaseFragment() { override fun bindPref() { // Incoming call sounds mUseRiotCallRingtonePreference.onPreferenceClickListener = Preference.OnPreferenceClickListener { - activity?.let { setUseRiotDefaultRingtone(it, mUseRiotCallRingtonePreference.isChecked) } + ringtoneUtils.setUseRiotDefaultRingtone(mUseRiotCallRingtonePreference.isChecked) false } mCallRingtonePreference.let { - activity?.let { activity -> it.summary = getCallRingtoneName(activity) } + it.summary = ringtoneUtils.getCallRingtoneName() it.onPreferenceClickListener = Preference.OnPreferenceClickListener { displayRingtonePicker() false @@ -68,10 +70,9 @@ class VectorSettingsVoiceVideoFragment : VectorSettingsBaseFragment() { private val ringtoneStartForActivityResult = registerStartForActivityResult { activityResult -> if (activityResult.resultCode == Activity.RESULT_OK) { val callRingtoneUri: Uri? = activityResult.data?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI) - val thisActivity = activity - if (callRingtoneUri != null && thisActivity != null) { - setCallRingtoneUri(thisActivity, callRingtoneUri) - mCallRingtonePreference.summary = getCallRingtoneName(thisActivity) + if (callRingtoneUri != null) { + ringtoneUtils.setCallRingtoneUri(callRingtoneUri) + mCallRingtonePreference.summary = ringtoneUtils.getCallRingtoneName() } } } @@ -82,7 +83,7 @@ class VectorSettingsVoiceVideoFragment : VectorSettingsBaseFragment() { putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_SILENT, false) putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, true) putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, RingtoneManager.TYPE_RINGTONE) - activity?.let { putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, getCallRingtoneUri(it)) } + putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, ringtoneUtils.getCallRingtoneUri()) } ringtoneStartForActivityResult.launch(intent) } diff --git a/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt b/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt index 96af7906e2..b5c7b162d8 100644 --- a/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt +++ b/vector/src/main/java/im/vector/app/features/themes/ThemeUtils.kt @@ -27,8 +27,8 @@ import androidx.annotation.ColorInt import androidx.core.content.ContextCompat import androidx.core.content.edit import androidx.core.graphics.drawable.DrawableCompat +import androidx.preference.PreferenceManager import im.vector.app.R -import im.vector.app.core.di.DefaultSharedPreferences import timber.log.Timber import java.util.concurrent.atomic.AtomicReference @@ -84,7 +84,7 @@ object ThemeUtils { fun getApplicationTheme(context: Context): String { val currentTheme = this.currentTheme.get() return if (currentTheme == null) { - val prefs = DefaultSharedPreferences.getInstance(context) + val prefs = PreferenceManager.getDefaultSharedPreferences(context.applicationContext) var themeFromPref = prefs.getString(APPLICATION_THEME_KEY, DEFAULT_THEME) ?: DEFAULT_THEME if (themeFromPref == "status") { // Migrate to the default theme From b4494ee8eafa84879a66e28cbdeca91fc2faa8fe Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 16:41:00 +0200 Subject: [PATCH 084/187] Remove `DefaultSharedPreferences` since we now have @DefaultPreferences which provide a singleton. Some fun has been moved to injectable classes due to this change. Not compiling, still work to do, but I prefer to split into 2 separate commits. --- .../im/vector/app/features/homeserver/ServerUrlsRepository.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt b/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt index 95e2aeedd1..65bf24dc45 100644 --- a/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt +++ b/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt @@ -85,7 +85,7 @@ class ServerUrlsRepository @Inject constructor( /** * Return true if url is the default homeserver url form resources. */ - fun isDefaultHomeServerUrl(context: Context, url: String) = url == getDefaultHomeServerUrl() + fun isDefaultHomeServerUrl(url: String) = url == getDefaultHomeServerUrl() /** * Return default homeserver url from resources. From c735ea5e3de53627d4c7d459bae837904d25b9ec Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 16:49:07 +0200 Subject: [PATCH 085/187] Remove duplication between `KeysBackupBanner.State` and `ServerBackupStatusViewModel.BannerState` and move the some logic to the ViewModel --- .../app/core/ui/views/KeysBackupBanner.kt | 116 +++--------------- .../restore/KeysBackupRestoreActivity.kt | 8 +- .../app/features/home/HomeDetailFragment.kt | 15 ++- .../features/home/NewHomeDetailFragment.kt | 15 ++- .../signout/ServerBackupStatusAction.kt | 25 ++++ .../signout/ServerBackupStatusViewModel.kt | 93 ++++++++++++-- 6 files changed, 156 insertions(+), 116 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusAction.kt diff --git a/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt b/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt index a753139c66..f0a42dd78d 100755 --- a/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt +++ b/vector/src/main/java/im/vector/app/core/ui/views/KeysBackupBanner.kt @@ -20,10 +20,10 @@ import android.content.Context import android.util.AttributeSet import android.view.View import androidx.constraintlayout.widget.ConstraintLayout -import androidx.core.content.edit import androidx.core.view.isVisible import im.vector.app.R import im.vector.app.databinding.ViewKeysBackupBannerBinding +import im.vector.app.features.workers.signout.BannerState import timber.log.Timber /** @@ -37,16 +37,12 @@ class KeysBackupBanner @JvmOverloads constructor( ) : ConstraintLayout(context, attrs, defStyleAttr), View.OnClickListener { var delegate: Delegate? = null - private var state: State = State.Initial + private var state: BannerState = BannerState.Initial private lateinit var views: ViewKeysBackupBannerBinding init { setupView() - DefaultSharedPreferences.getInstance(context).edit { - putBoolean(BANNER_SETUP_DO_NOT_SHOW_AGAIN, false) - putString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, "") - } } /** @@ -55,7 +51,7 @@ class KeysBackupBanner @JvmOverloads constructor( * @param newState the newState representing the view * @param force true to force the rendering of the view */ - fun render(newState: State, force: Boolean = false) { + fun render(newState: BannerState, force: Boolean = false) { if (newState == state && !force) { Timber.v("State unchanged") return @@ -66,48 +62,26 @@ class KeysBackupBanner @JvmOverloads constructor( hideAll() when (newState) { - State.Initial -> renderInitial() - State.Hidden -> renderHidden() - is State.Setup -> renderSetup(newState.numberOfKeys) - is State.Recover -> renderRecover(newState.version) - is State.Update -> renderUpdate(newState.version) - State.BackingUp -> renderBackingUp() + BannerState.Initial -> renderInitial() + BannerState.Hidden -> renderHidden() + is BannerState.Setup -> renderSetup(newState) + is BannerState.Recover -> renderRecover(newState) + is BannerState.Update -> renderUpdate(newState) + BannerState.BackingUp -> renderBackingUp() } } override fun onClick(v: View?) { when (state) { - is State.Setup -> delegate?.setupKeysBackup() - is State.Update, - is State.Recover -> delegate?.recoverKeysBackup() + is BannerState.Setup -> delegate?.setupKeysBackup() + is BannerState.Update, + is BannerState.Recover -> delegate?.recoverKeysBackup() else -> Unit } } private fun onCloseClicked() { - state.let { - when (it) { - is State.Setup -> { - DefaultSharedPreferences.getInstance(context).edit { - putBoolean(BANNER_SETUP_DO_NOT_SHOW_AGAIN, true) - } - } - is State.Recover -> { - DefaultSharedPreferences.getInstance(context).edit { - putString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, it.version) - } - } - is State.Update -> { - DefaultSharedPreferences.getInstance(context).edit { - putString(BANNER_UPDATE_DO_NOT_SHOW_FOR_VERSION, it.version) - } - } - else -> { - // Should not happen, close button is not displayed in other cases - } - } - } - + delegate?.onCloseClicked() // Force refresh render(state, true) } @@ -132,9 +106,8 @@ class KeysBackupBanner @JvmOverloads constructor( isVisible = false } - private fun renderSetup(nbOfKeys: Int) { - if (nbOfKeys == 0 || - DefaultSharedPreferences.getInstance(context).getBoolean(BANNER_SETUP_DO_NOT_SHOW_AGAIN, false)) { + private fun renderSetup(state: BannerState.Setup) { + if (state.numberOfKeys == 0 || state.doNotShowAgain) { // Do not display the setup banner if there is no keys to backup, or if the user has already closed it isVisible = false } else { @@ -147,8 +120,8 @@ class KeysBackupBanner @JvmOverloads constructor( } } - private fun renderRecover(version: String) { - if (version == DefaultSharedPreferences.getInstance(context).getString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, null)) { + private fun renderRecover(state: BannerState.Recover) { + if (state.version == state.doNotShowForVersion) { isVisible = false } else { isVisible = true @@ -160,8 +133,8 @@ class KeysBackupBanner @JvmOverloads constructor( } } - private fun renderUpdate(version: String) { - if (version == DefaultSharedPreferences.getInstance(context).getString(BANNER_UPDATE_DO_NOT_SHOW_FOR_VERSION, null)) { + private fun renderUpdate(state: BannerState.Update) { + if (state.version == state.doNotShowForVersion) { isVisible = false } else { isVisible = true @@ -190,61 +163,12 @@ class KeysBackupBanner @JvmOverloads constructor( views.viewKeysBackupBannerLoading.isVisible = false } - /** - * The state representing the view. - * It can take one state at a time. - */ - sealed class State { - // Not yet rendered - object Initial : State() - - // View will be Gone - object Hidden : State() - - // Keys backup is not setup, numberOfKeys is the number of locally stored keys - data class Setup(val numberOfKeys: Int) : State() - - // Keys backup can be recovered, with version from the server - data class Recover(val version: String) : State() - - // Keys backup can be updated - data class Update(val version: String) : State() - - // Keys are backing up - object BackingUp : State() - } - /** * An interface to delegate some actions to another object. */ interface Delegate { + fun onCloseClicked() fun setupKeysBackup() fun recoverKeysBackup() } - - companion object { - /** - * Preference key for setup. Value is a boolean. - */ - private const val BANNER_SETUP_DO_NOT_SHOW_AGAIN = "BANNER_SETUP_DO_NOT_SHOW_AGAIN" - - /** - * Preference key for recover. Value is a backup version (String). - */ - private const val BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION = "BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION" - - /** - * Preference key for update. Value is a backup version (String). - */ - private const val BANNER_UPDATE_DO_NOT_SHOW_FOR_VERSION = "BANNER_UPDATE_DO_NOT_SHOW_FOR_VERSION" - - /** - * Inform the banner that a Recover has been done for this version, so do not show the Recover banner for this version. - */ - fun onRecoverDoneForVersion(context: Context, version: String) { - DefaultSharedPreferences.getInstance(context).edit { - putString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, version) - } - } - } } diff --git a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt index 3089481255..c6e86f6f6b 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/keysbackup/restore/KeysBackupRestoreActivity.kt @@ -18,6 +18,7 @@ package im.vector.app.features.crypto.keysbackup.restore import android.app.Activity import android.content.Context import android.content.Intent +import com.airbnb.mvrx.viewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint import im.vector.app.R @@ -27,8 +28,9 @@ import im.vector.app.core.extensions.observeEvent import im.vector.app.core.extensions.registerStartForActivityResult import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.SimpleFragmentActivity -import im.vector.app.core.ui.views.KeysBackupBanner import im.vector.app.features.crypto.quads.SharedSecureStorageActivity +import im.vector.app.features.workers.signout.ServerBackupStatusAction +import im.vector.app.features.workers.signout.ServerBackupStatusViewModel import org.matrix.android.sdk.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME import javax.inject.Inject @@ -46,6 +48,7 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() { override fun getTitleRes() = R.string.title_activity_keys_backup_restore private lateinit var viewModel: KeysBackupRestoreSharedViewModel + private val serverBackupStatusViewModel: ServerBackupStatusViewModel by viewModel() override fun onBackPressed() { hideWaitingView() @@ -95,7 +98,8 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() { } KeysBackupRestoreSharedViewModel.NAVIGATE_TO_SUCCESS -> { viewModel.keyVersionResult.value?.version?.let { - KeysBackupBanner.onRecoverDoneForVersion(this, it) + // Inform the banner that a Recover has been done for this version, so do not show the Recover banner for this version. + serverBackupStatusViewModel.handle(ServerBackupStatusAction.OnRecoverDoneForVersion(it)) } replaceFragment(views.container, KeysBackupRestoreSuccessFragment::class.java, allowStateLoss = true) } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt index a2544a2fde..e824dc1820 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDetailFragment.kt @@ -56,6 +56,7 @@ import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorSettingsActivity.Companion.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY_MANAGE_SESSIONS import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.workers.signout.BannerState +import im.vector.app.features.workers.signout.ServerBackupStatusAction import im.vector.app.features.workers.signout.ServerBackupStatusViewModel import org.matrix.android.sdk.api.session.crypto.model.DeviceInfo import org.matrix.android.sdk.api.session.room.model.RoomSummary @@ -289,13 +290,15 @@ class HomeDetailFragment : } private fun setupKeysBackupBanner() { + serverBackupStatusViewModel.handle(ServerBackupStatusAction.OnBannerDisplayed) serverBackupStatusViewModel .onEach { when (val banState = it.bannerState.invoke()) { - is BannerState.Setup -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false) - BannerState.BackingUp -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false) - null, - BannerState.Hidden -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false) + is BannerState.Setup, + BannerState.BackingUp, + BannerState.Hidden -> views.homeKeysBackupBanner.render(banState, false) + null -> views.homeKeysBackupBanner.render(BannerState.Hidden, false) + else -> Unit /* No op? */ } } views.homeKeysBackupBanner.delegate = this @@ -402,6 +405,10 @@ class HomeDetailFragment : * KeysBackupBanner Listener * ========================================================================================== */ + override fun onCloseClicked() { + serverBackupStatusViewModel.handle(ServerBackupStatusAction.OnBannerClosed) + } + override fun setupKeysBackup() { navigator.openKeysBackupSetup(requireActivity(), false) } diff --git a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt index f31f8a7d92..66bb9ef876 100644 --- a/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/NewHomeDetailFragment.kt @@ -57,6 +57,7 @@ import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorSettingsActivity.Companion.EXTRA_DIRECT_ACCESS_SECURITY_PRIVACY_MANAGE_SESSIONS import im.vector.app.features.spaces.SpaceListBottomSheet import im.vector.app.features.workers.signout.BannerState +import im.vector.app.features.workers.signout.ServerBackupStatusAction import im.vector.app.features.workers.signout.ServerBackupStatusViewModel import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -300,13 +301,15 @@ class NewHomeDetailFragment : } private fun setupKeysBackupBanner() { + serverBackupStatusViewModel.handle(ServerBackupStatusAction.OnBannerDisplayed) serverBackupStatusViewModel .onEach { when (val banState = it.bannerState.invoke()) { - is BannerState.Setup -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Setup(banState.numberOfKeys), false) - BannerState.BackingUp -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.BackingUp, false) - null, - BannerState.Hidden -> views.homeKeysBackupBanner.render(KeysBackupBanner.State.Hidden, false) + is BannerState.Setup, + BannerState.BackingUp, + BannerState.Hidden -> views.homeKeysBackupBanner.render(banState, false) + null -> views.homeKeysBackupBanner.render(BannerState.Hidden, false) + else -> Unit /* No op? */ } } views.homeKeysBackupBanner.delegate = this @@ -348,6 +351,10 @@ class NewHomeDetailFragment : * KeysBackupBanner Listener * ========================================================================================== */ + override fun onCloseClicked() { + serverBackupStatusViewModel.handle(ServerBackupStatusAction.OnBannerClosed) + } + override fun setupKeysBackup() { navigator.openKeysBackupSetup(requireActivity(), false) } diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusAction.kt b/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusAction.kt new file mode 100644 index 0000000000..2c59a80964 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusAction.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.workers.signout + +import im.vector.app.core.platform.VectorViewModelAction + +sealed interface ServerBackupStatusAction : VectorViewModelAction { + data class OnRecoverDoneForVersion(val version: String) : ServerBackupStatusAction + object OnBannerDisplayed : ServerBackupStatusAction + object OnBannerClosed : ServerBackupStatusAction +} diff --git a/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt b/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt index d2a4b3193a..81cf48a832 100644 --- a/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/workers/signout/ServerBackupStatusViewModel.kt @@ -16,6 +16,8 @@ package im.vector.app.features.workers.signout +import android.content.SharedPreferences +import androidx.core.content.edit import androidx.lifecycle.MutableLiveData import com.airbnb.mvrx.Async import com.airbnb.mvrx.MavericksState @@ -24,9 +26,9 @@ import com.airbnb.mvrx.Uninitialized import dagger.assisted.Assisted import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject +import im.vector.app.core.di.DefaultPreferences import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory -import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel import kotlinx.coroutines.flow.MutableSharedFlow @@ -51,29 +53,55 @@ data class ServerBackupStatusViewState( * The state representing the view. * It can take one state at a time. */ -sealed class BannerState { +sealed interface BannerState { + // Not yet rendered + object Initial : BannerState - object Hidden : BannerState() + // View will be Gone + object Hidden : BannerState // Keys backup is not setup, numberOfKeys is the number of locally stored keys - data class Setup(val numberOfKeys: Int) : BannerState() + data class Setup(val numberOfKeys: Int, val doNotShowAgain: Boolean) : BannerState + + // Keys backup can be recovered, with version from the server + data class Recover(val version: String, val doNotShowForVersion: String) : BannerState + + // Keys backup can be updated + data class Update(val version: String, val doNotShowForVersion: String) : BannerState // Keys are backing up - object BackingUp : BannerState() + object BackingUp : BannerState } class ServerBackupStatusViewModel @AssistedInject constructor( @Assisted initialState: ServerBackupStatusViewState, - private val session: Session + private val session: Session, + @DefaultPreferences + private val sharedPreferences: SharedPreferences, ) : - VectorViewModel(initialState), KeysBackupStateListener { + VectorViewModel(initialState), KeysBackupStateListener { @AssistedFactory interface Factory : MavericksAssistedViewModelFactory { override fun create(initialState: ServerBackupStatusViewState): ServerBackupStatusViewModel } - companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() { + /** + * Preference key for setup. Value is a boolean. + */ + private const val BANNER_SETUP_DO_NOT_SHOW_AGAIN = "BANNER_SETUP_DO_NOT_SHOW_AGAIN" + + /** + * Preference key for recover. Value is a backup version (String). + */ + private const val BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION = "BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION" + + /** + * Preference key for update. Value is a backup version (String). + */ + private const val BANNER_UPDATE_DO_NOT_SHOW_FOR_VERSION = "BANNER_UPDATE_DO_NOT_SHOW_FOR_VERSION" + } // Keys exported manually val keysExportedToFile = MutableLiveData() @@ -105,7 +133,10 @@ class ServerBackupStatusViewModel @AssistedInject constructor( pInfo.getOrNull()?.allKnown().orFalse()) ) { // So 4S is not setup and we have local secrets, - return@combine BannerState.Setup(numberOfKeys = getNumberOfKeysToBackup()) + return@combine BannerState.Setup( + numberOfKeys = getNumberOfKeysToBackup(), + doNotShowAgain = sharedPreferences.getBoolean(BANNER_SETUP_DO_NOT_SHOW_AGAIN, false) + ) } BannerState.Hidden } @@ -161,5 +192,47 @@ class ServerBackupStatusViewModel @AssistedInject constructor( } } - override fun handle(action: EmptyAction) {} + override fun handle(action: ServerBackupStatusAction) { + when (action) { + is ServerBackupStatusAction.OnRecoverDoneForVersion -> handleOnRecoverDoneForVersion(action) + ServerBackupStatusAction.OnBannerDisplayed -> handleOnBannerDisplayed() + ServerBackupStatusAction.OnBannerClosed -> handleOnBannerClosed() + } + } + + private fun handleOnRecoverDoneForVersion(action: ServerBackupStatusAction.OnRecoverDoneForVersion) { + sharedPreferences.edit { + putString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, action.version) + } + } + + private fun handleOnBannerDisplayed() { + sharedPreferences.edit { + putBoolean(BANNER_SETUP_DO_NOT_SHOW_AGAIN, false) + putString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, "") + } + } + + private fun handleOnBannerClosed() = withState { state -> + when (val bannerState = state.bannerState()) { + is BannerState.Setup -> { + sharedPreferences.edit { + putBoolean(BANNER_SETUP_DO_NOT_SHOW_AGAIN, true) + } + } + is BannerState.Recover -> { + sharedPreferences.edit { + putString(BANNER_RECOVER_DO_NOT_SHOW_FOR_VERSION, bannerState.version) + } + } + is BannerState.Update -> { + sharedPreferences.edit { + putString(BANNER_UPDATE_DO_NOT_SHOW_FOR_VERSION, bannerState.version) + } + } + else -> { + // Should not happen, close button is not displayed in other cases + } + } + } } From 226672378959e970db25a09f418fa6653a8dd5c8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 17:03:46 +0200 Subject: [PATCH 086/187] Remove `DefaultSharedPreferences` since we now have @DefaultPreferences which provide a singleton. --- .../app/receivers/VectorDebugReceiver.kt | 19 +++++++++++-------- .../im/vector/app/push/fcm/GoogleFcmHelper.kt | 8 ++++---- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/vector-app/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt b/vector-app/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt index 550dc055d9..4edbdd0591 100644 --- a/vector-app/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt +++ b/vector-app/src/debug/java/im/vector/app/receivers/VectorDebugReceiver.kt @@ -23,7 +23,7 @@ import android.content.IntentFilter import android.content.SharedPreferences import androidx.core.content.edit import im.vector.app.core.debug.DebugReceiver -import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.di.DefaultPreferences import im.vector.app.core.utils.lsFiles import timber.log.Timber import javax.inject.Inject @@ -31,7 +31,10 @@ import javax.inject.Inject /** * Receiver to handle some command from ADB */ -class VectorDebugReceiver @Inject constructor() : BroadcastReceiver(), DebugReceiver { +class VectorDebugReceiver @Inject constructor( + @DefaultPreferences + private val sharedPreferences: SharedPreferences, +) : BroadcastReceiver(), DebugReceiver { override fun register(context: Context) { context.registerReceiver(this, getIntentFilter(context)) @@ -47,14 +50,14 @@ class VectorDebugReceiver @Inject constructor() : BroadcastReceiver(), DebugRece intent.action?.let { when { it.endsWith(DEBUG_ACTION_DUMP_FILESYSTEM) -> lsFiles(context) - it.endsWith(DEBUG_ACTION_DUMP_PREFERENCES) -> dumpPreferences(context) - it.endsWith(DEBUG_ACTION_ALTER_SCALAR_TOKEN) -> alterScalarToken(context) + it.endsWith(DEBUG_ACTION_DUMP_PREFERENCES) -> dumpPreferences() + it.endsWith(DEBUG_ACTION_ALTER_SCALAR_TOKEN) -> alterScalarToken() } } } - private fun dumpPreferences(context: Context) { - logPrefs("DefaultSharedPreferences", DefaultSharedPreferences.getInstance(context)) + private fun dumpPreferences() { + logPrefs("DefaultSharedPreferences", sharedPreferences) } private fun logPrefs(name: String, sharedPreferences: SharedPreferences?) { @@ -67,8 +70,8 @@ class VectorDebugReceiver @Inject constructor() : BroadcastReceiver(), DebugRece } } - private fun alterScalarToken(context: Context) { - DefaultSharedPreferences.getInstance(context).edit { + private fun alterScalarToken() { + sharedPreferences.edit { // putString("SCALAR_TOKEN_PREFERENCE_KEY" + Matrix.getInstance(context).defaultSession.myUserId, "bad_token") } } diff --git a/vector-app/src/gplay/java/im/vector/app/push/fcm/GoogleFcmHelper.kt b/vector-app/src/gplay/java/im/vector/app/push/fcm/GoogleFcmHelper.kt index d64847c124..7cf90cf874 100755 --- a/vector-app/src/gplay/java/im/vector/app/push/fcm/GoogleFcmHelper.kt +++ b/vector-app/src/gplay/java/im/vector/app/push/fcm/GoogleFcmHelper.kt @@ -17,6 +17,7 @@ package im.vector.app.push.fcm import android.app.Activity import android.content.Context +import android.content.SharedPreferences import android.widget.Toast import androidx.core.content.edit import com.google.android.gms.common.ConnectionResult @@ -24,7 +25,7 @@ import com.google.android.gms.common.GoogleApiAvailability import com.google.firebase.messaging.FirebaseMessaging import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder -import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.di.DefaultPreferences import im.vector.app.core.pushers.FcmHelper import im.vector.app.core.pushers.PushersManager import timber.log.Timber @@ -35,14 +36,13 @@ import javax.inject.Inject * It has an alter ego in the fdroid variant. */ class GoogleFcmHelper @Inject constructor( - context: Context, + @DefaultPreferences + private val sharedPrefs: SharedPreferences, ) : FcmHelper { companion object { private const val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN" } - private val sharedPrefs = DefaultSharedPreferences.getInstance(context) - override fun isFirebaseAvailable(): Boolean = true override fun getFcmToken(): String? { From 2bda97224cbf174759f4e81e1aa79f57db1dc7ed Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 17:15:43 +0200 Subject: [PATCH 087/187] Cleanup --- .../im/vector/app/features/homeserver/ServerUrlsRepository.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt b/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt index 65bf24dc45..636c557da9 100644 --- a/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt +++ b/vector/src/main/java/im/vector/app/features/homeserver/ServerUrlsRepository.kt @@ -16,7 +16,6 @@ package im.vector.app.features.homeserver -import android.content.Context import android.content.SharedPreferences import androidx.core.content.edit import im.vector.app.R From 0910b118ffa33b13421f017d356c2a9d8ba94671 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 17:20:03 +0200 Subject: [PATCH 088/187] Changelog --- changelog.d/7159.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7159.misc diff --git a/changelog.d/7159.misc b/changelog.d/7159.misc new file mode 100644 index 0000000000..76f5f45c40 --- /dev/null +++ b/changelog.d/7159.misc @@ -0,0 +1 @@ +Fix lint warning, and cleanup the code From 5886245bbffb6a77be4c864610b6f5ab305ca80b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 17:35:26 +0200 Subject: [PATCH 089/187] Reverse condition for code clarity with `ChecksSdkIntAtLeast` --- .../app/features/voice/VoiceRecorderProvider.kt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt b/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt index c024e0c6d4..05e537b2b0 100644 --- a/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt +++ b/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt @@ -33,18 +33,18 @@ class VoiceRecorderProvider @Inject constructor( private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider, ) { fun provideVoiceRecorder(): VoiceRecorder { - return if (useFallbackRecorder()) { - VoiceRecorderL(context, Dispatchers.IO) - } else { + return if (useNativeRecorder()) { VoiceRecorderQ(context) + } else { + VoiceRecorderL(context, Dispatchers.IO) } } - @ChecksSdkIntAtLeast(api = 29) - private fun useFallbackRecorder(): Boolean { - return buildVersionSdkIntProvider.get() < Build.VERSION_CODES.Q || - !hasOpusEncoder() || - vectorFeatures.forceUsageOfOpusEncoder() + @ChecksSdkIntAtLeast(api = Build.VERSION_CODES.Q) + private fun useNativeRecorder(): Boolean { + return buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.Q && + hasOpusEncoder() && + !vectorFeatures.forceUsageOfOpusEncoder() } @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE) From 658a09ea6aa24464b75646f0e82cca51d85d1c5a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 17:50:17 +0200 Subject: [PATCH 090/187] No need to use `@SuppressLint("NewApi")` when `@ChecksSdkIntAtLeast` is used. --- .../matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt | 3 +++ .../features/pin/lockscreen/crypto/LockScreenKeysMigrator.kt | 3 +-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt index acbf9ca061..c8c328c92c 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/util/BuildVersionSdkIntProvider.kt @@ -34,4 +34,7 @@ interface BuildVersionSdkIntProvider { result() } else null } + + @ChecksSdkIntAtLeast(parameter = 0) + fun isAtLeast(version: Int) = get() >= version } diff --git a/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/LockScreenKeysMigrator.kt b/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/LockScreenKeysMigrator.kt index bb55ceb1b7..84e98785f4 100644 --- a/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/LockScreenKeysMigrator.kt +++ b/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/LockScreenKeysMigrator.kt @@ -36,14 +36,13 @@ class LockScreenKeysMigrator @Inject constructor( /** * Performs any needed migrations in order. */ - @SuppressLint("NewApi") suspend fun migrateIfNeeded() { if (legacyPinCodeMigrator.isMigrationNeeded()) { legacyPinCodeMigrator.migrate() missingSystemKeyMigrator.migrateIfNeeded() } - if (systemKeyV1Migrator.isMigrationNeeded() && versionProvider.get() >= Build.VERSION_CODES.M) { + if (systemKeyV1Migrator.isMigrationNeeded() && versionProvider.isAtLeast(Build.VERSION_CODES.M)) { systemKeyV1Migrator.migrate() } } From 7f5c712e88b47261591408ac1009dba78ca47cfe Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 18:02:40 +0200 Subject: [PATCH 091/187] No need to use `@SuppressLint("NewApi")` when `@ChecksSdkIntAtLeast` is used - more cleanup --- .../api/securestorage/SecretStoringUtils.kt | 7 ++----- .../im/vector/app/core/extensions/Context.kt | 4 +--- .../VectorActivityLifecycleCallbacks.kt | 2 -- .../features/login/LoginCaptchaFragment.kt | 1 - .../notifications/NotificationUtils.kt | 3 --- .../onboarding/ftueauth/CaptchaWebview.kt | 1 - .../lockscreen/biometrics/BiometricHelper.kt | 2 -- .../pin/lockscreen/crypto/KeyStoreCrypto.kt | 5 +---- .../crypto/LockScreenKeysMigrator.kt | 1 - .../migrations/MissingSystemKeyMigrator.kt | 5 ++--- .../pin/lockscreen/ui/LockScreenViewModel.kt | 20 +++++++++---------- .../VectorSettingsSecurityPrivacyFragment.kt | 2 -- .../features/widgets/webview/WidgetWebView.kt | 2 -- 13 files changed, 15 insertions(+), 40 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecretStoringUtils.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecretStoringUtils.kt index e701e0f3ba..234a8eee98 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecretStoringUtils.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/securestorage/SecretStoringUtils.kt @@ -131,11 +131,10 @@ class SecretStoringUtils @Inject constructor( * * The secret is encrypted using the following method: AES/GCM/NoPadding */ - @SuppressLint("NewApi") @Throws(Exception::class) fun securelyStoreBytes(secret: ByteArray, keyAlias: String): ByteArray { return when { - buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M -> encryptBytesM(secret, keyAlias) + buildVersionSdkIntProvider.isAtLeast(Build.VERSION_CODES.M) -> encryptBytesM(secret, keyAlias) else -> encryptBytes(secret, keyAlias) } } @@ -156,10 +155,9 @@ class SecretStoringUtils @Inject constructor( } } - @SuppressLint("NewApi") fun securelyStoreObject(any: Any, keyAlias: String, output: OutputStream) { when { - buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M -> saveSecureObjectM(keyAlias, output, any) + buildVersionSdkIntProvider.isAtLeast(Build.VERSION_CODES.M) -> saveSecureObjectM(keyAlias, output, any) else -> saveSecureObject(keyAlias, output, any) } } @@ -189,7 +187,6 @@ class SecretStoringUtils @Inject constructor( return cipher } - @SuppressLint("NewApi") @RequiresApi(Build.VERSION_CODES.M) private fun getOrGenerateSymmetricKeyForAliasM(alias: String): SecretKey { val secretKeyEntry = (keyStore.getEntry(alias, null) as? KeyStore.SecretKeyEntry) diff --git a/vector/src/main/java/im/vector/app/core/extensions/Context.kt b/vector/src/main/java/im/vector/app/core/extensions/Context.kt index 1ed5aa8ba1..2e3e8c9306 100644 --- a/vector/src/main/java/im/vector/app/core/extensions/Context.kt +++ b/vector/src/main/java/im/vector/app/core/extensions/Context.kt @@ -16,7 +16,6 @@ package im.vector.app.core.extensions -import android.annotation.SuppressLint import android.content.Context import android.graphics.drawable.Drawable import android.net.ConnectivityManager @@ -91,10 +90,9 @@ fun Context.safeOpenOutputStream(uri: Uri): OutputStream? { * * @return true if no active connection is found */ -@SuppressLint("NewApi") // false positive fun Context.inferNoConnectivity(sdkIntProvider: BuildVersionSdkIntProvider): Boolean { val connectivityManager = getSystemService()!! - return if (sdkIntProvider.get() > Build.VERSION_CODES.M) { + return if (sdkIntProvider.isAtLeast(Build.VERSION_CODES.M)) { val networkCapabilities = connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork) when { networkCapabilities?.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) == true -> false diff --git a/vector/src/main/java/im/vector/app/features/lifecycle/VectorActivityLifecycleCallbacks.kt b/vector/src/main/java/im/vector/app/features/lifecycle/VectorActivityLifecycleCallbacks.kt index 75f02c36d7..c884843f5c 100644 --- a/vector/src/main/java/im/vector/app/features/lifecycle/VectorActivityLifecycleCallbacks.kt +++ b/vector/src/main/java/im/vector/app/features/lifecycle/VectorActivityLifecycleCallbacks.kt @@ -16,7 +16,6 @@ package im.vector.app.features.lifecycle -import android.annotation.SuppressLint import android.app.Activity import android.app.ActivityManager import android.app.Application @@ -91,7 +90,6 @@ class VectorActivityLifecycleCallbacks constructor(private val popupAlertManager * * @return true if an app task is corrupted by a potentially malicious activity */ - @SuppressLint("NewApi") private suspend fun isTaskCorrupted(activity: Activity): Boolean = withContext(Dispatchers.Default) { val context = activity.applicationContext val packageManager: PackageManager = context.packageManager diff --git a/vector/src/main/java/im/vector/app/features/login/LoginCaptchaFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginCaptchaFragment.kt index 25403b06f3..b082e37933 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginCaptchaFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginCaptchaFragment.kt @@ -144,7 +144,6 @@ class LoginCaptchaFragment : // runOnUiThread(Runnable { finish() }) } - @SuppressLint("NewApi") override fun onReceivedHttpError(view: WebView, request: WebResourceRequest, errorResponse: WebResourceResponse) { super.onReceivedHttpError(view, request, errorResponse) diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index cef94b5db2..7e91a89603 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -218,7 +218,6 @@ class NotificationUtils @Inject constructor( * @param withProgress true to show indeterminate progress on the notification * @return the polling thread listener notification */ - @SuppressLint("NewApi") fun buildForegroundServiceNotification(@StringRes subTitleResId: Int, withProgress: Boolean = true): Notification { // build the pending intent go to the home screen if this is clicked. val i = HomeActivity.newIntent(context, firstStartMainActivity = false) @@ -287,7 +286,6 @@ class NotificationUtils @Inject constructor( * @param fromBg true if the app is in background when posting the notification * @return the call notification. */ - @SuppressLint("NewApi") fun buildIncomingCallNotification( call: WebRtcCall, title: String, @@ -420,7 +418,6 @@ class NotificationUtils @Inject constructor( * @param title title of the notification * @return the call notification. */ - @SuppressLint("NewApi") fun buildPendingCallNotification( call: WebRtcCall, title: String diff --git a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/CaptchaWebview.kt b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/CaptchaWebview.kt index 23c6c13b5e..11f257c4e8 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/CaptchaWebview.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/ftueauth/CaptchaWebview.kt @@ -92,7 +92,6 @@ class CaptchaWebview @Inject constructor( Timber.e("## onError() : $errorMessage") } - @SuppressLint("NewApi") override fun onReceivedHttpError(view: WebView, request: WebResourceRequest, errorResponse: WebResourceResponse) { super.onReceivedHttpError(view, request, errorResponse) when { diff --git a/vector/src/main/java/im/vector/app/features/pin/lockscreen/biometrics/BiometricHelper.kt b/vector/src/main/java/im/vector/app/features/pin/lockscreen/biometrics/BiometricHelper.kt index 9bcf6e4264..026ee159ed 100644 --- a/vector/src/main/java/im/vector/app/features/pin/lockscreen/biometrics/BiometricHelper.kt +++ b/vector/src/main/java/im/vector/app/features/pin/lockscreen/biometrics/BiometricHelper.kt @@ -16,7 +16,6 @@ package im.vector.app.features.pin.lockscreen.biometrics -import android.annotation.SuppressLint import android.content.Context import android.os.Build import androidx.annotation.MainThread @@ -156,7 +155,6 @@ class BiometricHelper @AssistedInject constructor( return authenticate(activity) } - @SuppressLint("NewApi") @OptIn(ExperimentalCoroutinesApi::class) private fun authenticateInternal( activity: FragmentActivity, diff --git a/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/KeyStoreCrypto.kt b/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/KeyStoreCrypto.kt index a42ce3a9b7..fd676f1662 100644 --- a/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/KeyStoreCrypto.kt +++ b/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/KeyStoreCrypto.kt @@ -16,7 +16,6 @@ package im.vector.app.features.pin.lockscreen.crypto -import android.annotation.SuppressLint import android.content.Context import android.os.Build import android.security.keystore.KeyPermanentlyInvalidatedException @@ -55,7 +54,6 @@ class KeyStoreCrypto @AssistedInject constructor( * Ensures a [Key] for the [alias] exists and validates it. * @throws KeyPermanentlyInvalidatedException if key is not valid. */ - @SuppressLint("NewApi") @Throws(KeyPermanentlyInvalidatedException::class) fun ensureKey() = secretStoringUtils.ensureKey(alias).also { // Check validity of Key by initializing an encryption Cipher @@ -109,10 +107,9 @@ class KeyStoreCrypto @AssistedInject constructor( /** * Check if the key associated with the [alias] is valid. */ - @SuppressLint("NewApi") fun hasValidKey(): Boolean { val keyExists = hasKey() - return if (buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M && keyExists) { + return if (buildVersionSdkIntProvider.isAtLeast(Build.VERSION_CODES.M) && keyExists) { val initializedKey = tryOrNull("Error validating lockscreen system key.") { ensureKey() } initializedKey != null } else { diff --git a/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/LockScreenKeysMigrator.kt b/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/LockScreenKeysMigrator.kt index 84e98785f4..c2d70a3734 100644 --- a/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/LockScreenKeysMigrator.kt +++ b/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/LockScreenKeysMigrator.kt @@ -16,7 +16,6 @@ package im.vector.app.features.pin.lockscreen.crypto -import android.annotation.SuppressLint import android.os.Build import im.vector.app.features.pin.lockscreen.crypto.migrations.LegacyPinCodeMigrator import im.vector.app.features.pin.lockscreen.crypto.migrations.MissingSystemKeyMigrator diff --git a/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/migrations/MissingSystemKeyMigrator.kt b/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/migrations/MissingSystemKeyMigrator.kt index 4c33c14954..7593aa6de3 100644 --- a/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/migrations/MissingSystemKeyMigrator.kt +++ b/vector/src/main/java/im/vector/app/features/pin/lockscreen/crypto/migrations/MissingSystemKeyMigrator.kt @@ -16,7 +16,6 @@ package im.vector.app.features.pin.lockscreen.crypto.migrations -import android.annotation.SuppressLint import android.os.Build import im.vector.app.features.pin.lockscreen.crypto.KeyStoreCrypto import im.vector.app.features.pin.lockscreen.di.BiometricKeyAlias @@ -38,9 +37,9 @@ class MissingSystemKeyMigrator @Inject constructor( /** * If user had biometric auth enabled, ensure system key exists, creating one if needed. */ - @SuppressLint("NewApi") fun migrateIfNeeded() { - if (buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M && vectorPreferences.useBiometricsToUnlock()) { + if (buildVersionSdkIntProvider.isAtLeast(Build.VERSION_CODES.M) && + vectorPreferences.useBiometricsToUnlock()) { val systemKeyStoreCrypto = keystoreCryptoFactory.provide(systemKeyAlias, true) runCatching { systemKeyStoreCrypto.ensureKey() diff --git a/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/LockScreenViewModel.kt b/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/LockScreenViewModel.kt index 33ea590f1d..87d3f93f9b 100644 --- a/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/LockScreenViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/pin/lockscreen/ui/LockScreenViewModel.kt @@ -16,7 +16,6 @@ package im.vector.app.features.pin.lockscreen.ui -import android.annotation.SuppressLint import android.app.KeyguardManager import android.os.Build import android.security.keystore.KeyPermanentlyInvalidatedException @@ -139,12 +138,12 @@ class LockScreenViewModel @AssistedInject constructor( } }.launchIn(viewModelScope) - @SuppressLint("NewApi") private fun showBiometricPrompt(activity: FragmentActivity) = flow { emitAll(biometricHelper.authenticate(activity)) }.catch { error -> when { - versionProvider.get() >= Build.VERSION_CODES.M && error is KeyPermanentlyInvalidatedException -> { + versionProvider.isAtLeast(Build.VERSION_CODES.M) && + error is KeyPermanentlyInvalidatedException -> { onBiometricKeyInvalidated() } else -> { @@ -168,15 +167,14 @@ class LockScreenViewModel @AssistedInject constructor( _viewEvents.post(LockScreenViewEvent.ShowBiometricKeyInvalidatedMessage) } - @SuppressLint("NewApi") private suspend fun updateStateWithBiometricInfo() { // This is a terrible hack, but I found no other way to ensure this would be called only after the device is considered unlocked on Android 12+ waitUntilKeyguardIsUnlocked() setState { val isBiometricKeyInvalidated = biometricHelper.hasSystemKey && !biometricHelper.isSystemKeyValid val canUseBiometricAuth = lockScreenConfiguration.mode == LockScreenMode.VERIFY && - !isSystemAuthTemporarilyDisabledByBiometricPrompt && - biometricHelper.isSystemAuthEnabledAndValid + !isSystemAuthTemporarilyDisabledByBiometricPrompt && + biometricHelper.isSystemAuthEnabledAndValid val showBiometricPromptAutomatically = canUseBiometricAuth && lockScreenConfiguration.autoStartBiometric copy( canUseBiometricAuth = canUseBiometricAuth, @@ -191,12 +189,12 @@ class LockScreenViewModel @AssistedInject constructor( * after an Activity's `onResume` method. If we mix that with the system keys needing the device to be unlocked before they're used, we get crashes. * See issue [#6768](https://github.com/vector-im/element-android/issues/6768). */ - @SuppressLint("NewApi") private suspend fun waitUntilKeyguardIsUnlocked() { - if (versionProvider.get() < Build.VERSION_CODES.S) return - withTimeoutOrNull(5.seconds) { - while (keyguardManager.isDeviceLocked) { - delay(50.milliseconds) + if (versionProvider.isAtLeast(Build.VERSION_CODES.S)) { + withTimeoutOrNull(5.seconds) { + while (keyguardManager.isDeviceLocked) { + delay(50.milliseconds) + } } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt index ecb1779a4a..5cbdf114a5 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -17,7 +17,6 @@ package im.vector.app.features.settings -import android.annotation.SuppressLint import android.app.Activity import android.content.Intent import android.net.Uri @@ -448,7 +447,6 @@ class VectorSettingsSecurityPrivacyFragment : /** * Manage the e2e keys import. */ - @SuppressLint("NewApi") private fun importKeys() { openFileSelection( requireActivity(), diff --git a/vector/src/main/java/im/vector/app/features/widgets/webview/WidgetWebView.kt b/vector/src/main/java/im/vector/app/features/widgets/webview/WidgetWebView.kt index ac9930866f..254a7f97f5 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/webview/WidgetWebView.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/webview/WidgetWebView.kt @@ -16,7 +16,6 @@ package im.vector.app.features.widgets.webview -import android.annotation.SuppressLint import android.app.Activity import android.view.ViewGroup import android.webkit.CookieManager @@ -29,7 +28,6 @@ import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.webview.VectorWebViewClient import im.vector.app.features.webview.WebEventListener -@SuppressLint("NewApi") fun WebView.setupForWidget(activity: Activity, checkWebViewPermissionsUseCase: CheckWebViewPermissionsUseCase, eventListener: WebEventListener, From 0559911f39e7cf537b1c3cdaad6b207d1699478d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 22:53:32 +0200 Subject: [PATCH 092/187] Fix non passing tests --- .../app/TestBuildVersionSdkIntProvider.kt | 4 +--- .../migrations/LegacyPinCodeMigratorTests.kt | 23 +++++++++---------- 2 files changed, 12 insertions(+), 15 deletions(-) diff --git a/vector/src/androidTest/java/im/vector/app/TestBuildVersionSdkIntProvider.kt b/vector/src/androidTest/java/im/vector/app/TestBuildVersionSdkIntProvider.kt index ddf89b5e46..b3f9c65800 100644 --- a/vector/src/androidTest/java/im/vector/app/TestBuildVersionSdkIntProvider.kt +++ b/vector/src/androidTest/java/im/vector/app/TestBuildVersionSdkIntProvider.kt @@ -18,8 +18,6 @@ package im.vector.app import org.matrix.android.sdk.api.util.BuildVersionSdkIntProvider -class TestBuildVersionSdkIntProvider : BuildVersionSdkIntProvider { - var value: Int = 0 - +class TestBuildVersionSdkIntProvider(var value: Int = 0) : BuildVersionSdkIntProvider { override fun get() = value } diff --git a/vector/src/androidTest/java/im/vector/app/features/pin/lockscreen/crypto/migrations/LegacyPinCodeMigratorTests.kt b/vector/src/androidTest/java/im/vector/app/features/pin/lockscreen/crypto/migrations/LegacyPinCodeMigratorTests.kt index 44c5db89c8..5f1ba8876a 100644 --- a/vector/src/androidTest/java/im/vector/app/features/pin/lockscreen/crypto/migrations/LegacyPinCodeMigratorTests.kt +++ b/vector/src/androidTest/java/im/vector/app/features/pin/lockscreen/crypto/migrations/LegacyPinCodeMigratorTests.kt @@ -25,6 +25,7 @@ import android.security.keystore.KeyProperties import android.util.Base64 import androidx.preference.PreferenceManager import androidx.test.platform.app.InstrumentationRegistry +import im.vector.app.TestBuildVersionSdkIntProvider import im.vector.app.features.pin.PinCodeStore import im.vector.app.features.pin.SharedPrefPinCodeStore import im.vector.app.features.pin.lockscreen.crypto.LockScreenCryptoConstants.ANDROID_KEY_STORE @@ -32,7 +33,6 @@ import im.vector.app.features.pin.lockscreen.crypto.LockScreenCryptoConstants.LE import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every -import io.mockk.mockk import io.mockk.spyk import io.mockk.verify import kotlinx.coroutines.runBlocking @@ -42,7 +42,6 @@ import org.amshove.kluent.shouldBeEqualTo import org.junit.After import org.junit.Test import org.matrix.android.sdk.api.securestorage.SecretStoringUtils -import org.matrix.android.sdk.api.util.BuildVersionSdkIntProvider import java.math.BigInteger import java.security.KeyFactory import java.security.KeyPairGenerator @@ -66,9 +65,7 @@ class LegacyPinCodeMigratorTests { SharedPrefPinCodeStore(PreferenceManager.getDefaultSharedPreferences(InstrumentationRegistry.getInstrumentation().context)) ) private val keyStore: KeyStore = spyk(KeyStore.getInstance(ANDROID_KEY_STORE)).also { it.load(null) } - private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider = mockk { - every { get() } returns Build.VERSION_CODES.M - } + private val buildVersionSdkIntProvider = TestBuildVersionSdkIntProvider(Build.VERSION_CODES.M) private val secretStoringUtils: SecretStoringUtils = spyk( SecretStoringUtils(context, keyStore, buildVersionSdkIntProvider) ) @@ -126,6 +123,7 @@ class LegacyPinCodeMigratorTests { @Test fun migratePinCodeM() = runTest { val pinCode = "1234" + buildVersionSdkIntProvider.value = Build.VERSION_CODES.M saveLegacyPinCode(pinCode) legacyPinCodeMigrator.migrate() @@ -144,7 +142,7 @@ class LegacyPinCodeMigratorTests { @Test fun migratePinCodeL() = runTest { val pinCode = "1234" - every { buildVersionSdkIntProvider.get() } returns Build.VERSION_CODES.LOLLIPOP + buildVersionSdkIntProvider.value = Build.VERSION_CODES.LOLLIPOP saveLegacyPinCode(pinCode) legacyPinCodeMigrator.migrate() @@ -163,7 +161,7 @@ class LegacyPinCodeMigratorTests { private fun generateLegacyKey() { if (keyStore.containsAlias(LEGACY_PIN_CODE_KEY_ALIAS)) return - if (buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M) { + if (buildVersionSdkIntProvider.isAtLeast(Build.VERSION_CODES.M)) { generateLegacyKeyM() } else { generateLegacyKeyL() @@ -206,7 +204,7 @@ class LegacyPinCodeMigratorTests { generateLegacyKey() val publicKey = keyStore.getCertificate(LEGACY_PIN_CODE_KEY_ALIAS).publicKey val cipher = getLegacyCipher() - if (buildVersionSdkIntProvider.get() >= Build.VERSION_CODES.M) { + if (buildVersionSdkIntProvider.isAtLeast(Build.VERSION_CODES.M)) { val unrestrictedKey = KeyFactory.getInstance(publicKey.algorithm).generatePublic(X509EncodedKeySpec(publicKey.encoded)) val spec = OAEPParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT) cipher.init(Cipher.ENCRYPT_MODE, unrestrictedKey, spec) @@ -219,14 +217,15 @@ class LegacyPinCodeMigratorTests { } private fun getLegacyCipher(): Cipher { - return when (buildVersionSdkIntProvider.get()) { - Build.VERSION_CODES.LOLLIPOP, Build.VERSION_CODES.LOLLIPOP_MR1 -> getCipherL() - else -> getCipherM() + return if (buildVersionSdkIntProvider.isAtLeast(Build.VERSION_CODES.M)) { + getCipherM() + } else { + getCipherL() } } private fun getCipherL(): Cipher { - val provider = if (buildVersionSdkIntProvider.get() < Build.VERSION_CODES.M) "AndroidOpenSSL" else "AndroidKeyStoreBCWorkaround" + val provider = if (buildVersionSdkIntProvider.isAtLeast(Build.VERSION_CODES.M)) "AndroidKeyStoreBCWorkaround" else "AndroidOpenSSL" val transformation = "RSA/ECB/PKCS1Padding" return Cipher.getInstance(transformation, provider) } From 3600e374f2a20f3536e228ab312fb7025d563e30 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 16 Sep 2022 22:54:49 +0200 Subject: [PATCH 093/187] Avoid code duplication --- .../migrations/LegacyPinCodeMigratorTests.kt | 21 ++++++------------- 1 file changed, 6 insertions(+), 15 deletions(-) diff --git a/vector/src/androidTest/java/im/vector/app/features/pin/lockscreen/crypto/migrations/LegacyPinCodeMigratorTests.kt b/vector/src/androidTest/java/im/vector/app/features/pin/lockscreen/crypto/migrations/LegacyPinCodeMigratorTests.kt index 5f1ba8876a..8c50806fd9 100644 --- a/vector/src/androidTest/java/im/vector/app/features/pin/lockscreen/crypto/migrations/LegacyPinCodeMigratorTests.kt +++ b/vector/src/androidTest/java/im/vector/app/features/pin/lockscreen/crypto/migrations/LegacyPinCodeMigratorTests.kt @@ -122,27 +122,18 @@ class LegacyPinCodeMigratorTests { @Test fun migratePinCodeM() = runTest { - val pinCode = "1234" buildVersionSdkIntProvider.value = Build.VERSION_CODES.M - saveLegacyPinCode(pinCode) - - legacyPinCodeMigrator.migrate() - - coVerify { legacyPinCodeMigrator.getDecryptedPinCode() } - verify { secretStoringUtils.securelyStoreBytes(any(), any()) } - coVerify { pinCodeStore.savePinCode(any()) } - verify { keyStore.deleteEntry(LEGACY_PIN_CODE_KEY_ALIAS) } - - val decodedPinCode = String(secretStoringUtils.loadSecureSecretBytes(Base64.decode(pinCodeStore.getPinCode().orEmpty(), Base64.NO_WRAP), alias)) - decodedPinCode shouldBeEqualTo pinCode - keyStore.containsAlias(LEGACY_PIN_CODE_KEY_ALIAS) shouldBe false - keyStore.containsAlias(alias) shouldBe true + migratePinCode() } @Test fun migratePinCodeL() = runTest { - val pinCode = "1234" buildVersionSdkIntProvider.value = Build.VERSION_CODES.LOLLIPOP + migratePinCode() + } + + private suspend fun migratePinCode() { + val pinCode = "1234" saveLegacyPinCode(pinCode) legacyPinCodeMigrator.migrate() From 086a6ee9a1ec233223d7420a1769e8ff6787f024 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Sep 2022 16:39:35 +0200 Subject: [PATCH 094/187] Update after Ganfra's review --- docs/_developer_onboarding.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/_developer_onboarding.md b/docs/_developer_onboarding.md index 543cbeba71..8836b019b7 100644 --- a/docs/_developer_onboarding.md +++ b/docs/_developer_onboarding.md @@ -61,14 +61,14 @@ There are many object and data in the Matrix worlds. Let's focus on the most imp ##### Event -`Events` are item of a Room, where data is embedded. +`Events` are items of a Room, where data is embedded. -There are 2 types of Event: +There are 2 types of Room Event: -- Room Events: contain useful content for the user (message, image, etc.), but are not necessarily displayed as this in the timeline (reaction, message edition, call signaling). +- Regular Events: contain useful content for the user (message, image, etc.), but are not necessarily displayed as this in the timeline (reaction, message edition, call signaling). - State Events: contain the state of the Room (name, topic, etc.). They have a non null value for the key `state_key`. -Also all the Room Member details are State Events: one State Event per member. In this casen the `state_key` is the matrixId (= userId). +Also all the Room Member details are in State Events: one State Event per member. In this case, the `state_key` is the matrixId (= userId). Important Fields of an Event: - `event_id`: unique across the Matrix universe; From 828413c2c5b4b7a28f6d7a5b30a5bbed6bda3fbb Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Sep 2022 16:40:34 +0200 Subject: [PATCH 095/187] Fix some typo --- docs/_developer_onboarding.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/_developer_onboarding.md b/docs/_developer_onboarding.md index 8836b019b7..2f414063e3 100644 --- a/docs/_developer_onboarding.md +++ b/docs/_developer_onboarding.md @@ -100,7 +100,7 @@ The project should compile out of the box. The project is split into several modules. The main ones are: For the app - `vector-app`: application entry point; -- `vector`: legacy application, but now a library. In the process of being splitted into several modules; +- `vector`: legacy application, but now a library. In the process of being split into several modules; - `vector-config`: this is where all the configuration of the application should occurs. Should because we are in the process of migrating all the configuration here; - `library/ui-strings`: this is where all the string resources are stored. Please refer to [contributing doc](../CONTRIBUTING.md) to know how to make change on this module; - `library/ui-styles`: this is where the Android styles are defined. @@ -197,7 +197,7 @@ This is the classical scenario: All the dependencies are declared in `build.gradle` files. But some versions are declared in [this dedicated file](../dependencies.gradle). -When adding a new dependency, you will have to update the file [dependencies_groups.gradle](../dependencies_groups.gradle) to allow the dependency to be downloaded from the artifact repository. Sometimes subdependencies need to be added too, until the project can compile. +When adding a new dependency, you will have to update the file [dependencies_groups.gradle](../dependencies_groups.gradle) to allow the dependency to be downloaded from the artifact repository. Sometimes sub-dependencies need to be added too, until the project can compile. [Dependabot](https://github.com/dependabot) is set up on the project. This tool will automatically create Pull Request to upgrade our dependencies one by one. dependencies_group, gradle files, Dependabot, etc. @@ -243,7 +243,7 @@ Rageshake can be very useful to get logs from a release version of the applicati ### Tips - Element Android has a `developer mode` in the `Settings/Advanced settings`. Other useful options are available here; -- Show hidden Events can also help to debug feature. When devepor mode is enabled, it is possible to view the source (= the Json content) of any Events; +- Show hidden Events can also help to debug feature. When developer mode is enabled, it is possible to view the source (= the Json content) of any Events; - Type `/devtools` in a Room composer to access a developer menu. There are some other entry points. Developer mode has to be enabled; - Hidden debug menu: when developer mode is enabled and on debug build, there are some extra screens that can be accessible using the green wheel. In those screens, it will be possible to toggle some feature flags; - Using logcat, filtering with `onResume` can help you to understand what screen are currently displayed on your device. Searching for string displayed on the screen can also help to find the running code in the codebase. From cefe2e9ef49fff5cc5b0566a642dff4e3237ebae Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Sep 2022 17:03:45 +0200 Subject: [PATCH 096/187] Add a rule to Danger to check that translation files are not modified by developers. --- docs/danger.md | 1 + tools/danger/dangerfile.js | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/docs/danger.md b/docs/danger.md index afa3555469..34baa62e9e 100644 --- a/docs/danger.md +++ b/docs/danger.md @@ -28,6 +28,7 @@ Here are the checks that Danger does so far: - PR with change on layout should include screenshot in the description - PR which adds png file warn about the usage of vector drawables - non draft PR should have a reviewer +- files containing translations are not modified by developers ### Quality check diff --git a/tools/danger/dangerfile.js b/tools/danger/dangerfile.js index c7db52fa19..6314ec8f68 100644 --- a/tools/danger/dangerfile.js +++ b/tools/danger/dangerfile.js @@ -118,3 +118,10 @@ if (hasPngs) { if (github.requested_reviewers.users.length == 0 && !pr.draft) { warn("Please add a reviewer to your PR.") } + +// Check that translations have not been modified by developers +if (user != "RiotTranslateBot") { + if (editedFiles.some(file => file.endsWith("strings.xml") && !file.endsWith("values/strings.xml"))) { + fail("Some translation files have been edited. Only user `RiotTranslateBot` (i.e. translations coming from Weblate) is allowed to do that.\nPlease read more about translations management [in the doc](https://github.com/vector-im/element-android/blob/develop/CONTRIBUTING.md#internationalisation).") + } +} From a7856db218db6c24fb186383a364259db522f092 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Sep 2022 17:10:46 +0200 Subject: [PATCH 097/187] Add a section about renaming id of String resource --- CONTRIBUTING.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 52ccf47e6a..e01e1affe8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -120,7 +120,7 @@ You should consider adding Unit tests with your PR, and also integration tests ( Translations are handled using an external tool: [Weblate](https://translate.element.io/projects/element-android/) -As a general rule, please never edit or add or remove translations to the project in a Pull Request. It can lead to merge conflict if the translations are also modified in Weblate side. +**As a general rule, please never edit or add or remove translations to the project in a Pull Request**. It can lead to merge conflict if the translations are also modified in Weblate side. Pull Request containing change(s) on the translation files cannot be merged. #### Adding new string @@ -150,6 +150,17 @@ And add `tools:ignore="UnusedResources"` to the string, to let lint ignore that The string will be removed during the next sync with Weblate. +#### Renaming string ids + +This is possible to rename ids of the String resources, but since translation files cannot be edited, add TODO in the main strings.xml file above the strings you want to rename. + +```xml + +Hello Matrix world! +``` + +The string id(s) will be renamed during the next Weblate sync. + ### Accessibility Please consider accessibility as an important point. As a minimum requirement, in layout XML files please use attributes such as `android:contentDescription` and `android:importantForAccessibility`, and test with a screen reader if it's working well. You can add new string resources, dedicated to accessibility, in this case, please prefix theirs id with `a11y_`. From 729eba750ba5f5faf0241627dd8e018dfcfd12f1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Sep 2022 17:19:57 +0200 Subject: [PATCH 098/187] Add link to the file values/strings.xml, and fix typo in the path. --- CONTRIBUTING.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e01e1affe8..11f6a93dd1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -124,11 +124,11 @@ Translations are handled using an external tool: [Weblate](https://translate.ele #### Adding new string -When adding new string resources, please only add new entries in the file `value/strings.xml`. Translations will be added later by the community of translators using Weblate. +When adding new string resources, please only add new entries in the file `values/strings.xml` ([this file](./library/ui-strings/src/main/res/values/strings.xml)). Translations will be added later by the community of translators using Weblate. -The file `value/strings.xml` must only contain American English (U. S. English) values, as this is the default language of the Android operating system. So for instance, please use "color" instead of "colour". Element Android will still use the language set on the system by the user, like any other Android applications which provide translations. The system language can be any other English language variants, or any other languages. Note that this is also possible to override the system language using the Element Android in-app language settings. +The file `values/strings.xml` must only contain American English (U. S. English) values, as this is the default language of the Android operating system. So for instance, please use "color" instead of "colour". Element Android will still use the language set on the system by the user, like any other Android applications which provide translations. The system language can be any other English language variants, or any other languages. Note that this is also possible to override the system language using the Element Android in-app language settings. -New strings can be added anywhere in the file `value/strings.xml`, not necessarily at the end of the file. Generally, it's even better to add the new strings in some dedicated section per feature, and not at the end of the file, to avoid merge conflict between 2 PR adding strings at the end of the same file. +New strings can be added anywhere in the file `values/strings.xml`, not necessarily at the end of the file. Generally, it's even better to add the new strings in some dedicated section per feature, and not at the end of the file, to avoid merge conflict between 2 PR adding strings at the end of the same file. Do not hesitate to use plurals when appropriate. From 97c3623f89af7fece9674c410eb3af8ab1b7cbea Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Sep 2022 17:15:13 +0200 Subject: [PATCH 099/187] Add a note for plurals --- CONTRIBUTING.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 11f6a93dd1..c3df2b7101 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -130,7 +130,11 @@ The file `values/strings.xml` must only contain American English (U. S. English) New strings can be added anywhere in the file `values/strings.xml`, not necessarily at the end of the file. Generally, it's even better to add the new strings in some dedicated section per feature, and not at the end of the file, to avoid merge conflict between 2 PR adding strings at the end of the same file. -Do not hesitate to use plurals when appropriate. +##### Plurals + +Please use `plurals` resources when appropriate, and note that some languages have specific rules for `plurals`, so even if the string will always be at the plural form for English, please always create a `plurals` resource. + +Specific plural forms can be found [here](https://unicode-org.github.io/cldr-staging/charts/37/supplemental/language_plural_rules.html). #### Editing existing strings From 6e2ce10f655a16532c57ca464744e282c2c43e24 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Sep 2022 17:22:17 +0200 Subject: [PATCH 100/187] Add a note for string reordering --- CONTRIBUTING.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c3df2b7101..8f193c4b72 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -165,6 +165,12 @@ This is possible to rename ids of the String resources, but since translation fi The string id(s) will be renamed during the next Weblate sync. +#### Reordering strings + +To group strings per feature, or for any other reasons, it is possible to reorder string resources, but only in the [main strings.xml file](./library/ui-strings/src/main/res/values/strings.xml). ). We do not mind about ordering in the translation files, and anyway this is forbidden to edit manually the translation files. + +It is also possible to add empty lines between string resources, and to add XML comments. Please note that the XML comment just above a String resource will also appear on Weblate and be visible to the translators. + ### Accessibility Please consider accessibility as an important point. As a minimum requirement, in layout XML files please use attributes such as `android:contentDescription` and `android:importantForAccessibility`, and test with a screen reader if it's working well. You can add new string resources, dedicated to accessibility, in this case, please prefix theirs id with `a11y_`. From c56f33a9398c37db74cf5ba84975f27ce58431c8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Sep 2022 17:36:08 +0200 Subject: [PATCH 101/187] Add changelog --- changelog.d/7211.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7211.misc diff --git a/changelog.d/7211.misc b/changelog.d/7211.misc new file mode 100644 index 0000000000..44abd3d59d --- /dev/null +++ b/changelog.d/7211.misc @@ -0,0 +1 @@ + CI: Prevent modification of translations by developer. From a07761dedb25a73085cc13159e6378077ee5a6c7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Sep 2022 17:48:38 +0200 Subject: [PATCH 102/187] Fix issue with knit. --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8f193c4b72..b71e697636 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -159,7 +159,7 @@ The string will be removed during the next sync with Weblate. This is possible to rename ids of the String resources, but since translation files cannot be edited, add TODO in the main strings.xml file above the strings you want to rename. ```xml - + Hello Matrix world! ``` From a5ab942097cbf462b56e99e5457cccc8a61d4d4b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Sep 2022 17:52:52 +0200 Subject: [PATCH 103/187] Add TOC to CONTRIBUTING.md --- CONTRIBUTING.md | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b71e697636..6e3c784dac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,10 +1,42 @@ -# Contributing code to Matrix +# Contributing to Element Android + + + +* [Contributing code to Matrix](#contributing-code-to-matrix) +* [Android Studio settings](#android-studio-settings) + * [Template](#template) +* [Compilation](#compilation) +* [I want to help translating Element](#i-want-to-help-translating-element) +* [I want to submit a PR to fix an issue](#i-want-to-submit-a-pr-to-fix-an-issue) + * [Kotlin](#kotlin) + * [Changelog](#changelog) + * [Code quality](#code-quality) + * [Internal tool](#internal-tool) + * [ktlint](#ktlint) + * [lint](#lint) + * [Unit tests](#unit-tests) + * [Tests](#tests) + * [Internationalisation](#internationalisation) + * [Adding new string](#adding-new-string) + * [Plurals](#plurals) + * [Editing existing strings](#editing-existing-strings) + * [Removing existing strings](#removing-existing-strings) + * [Renaming string ids](#renaming-string-ids) + * [Reordering strings](#reordering-strings) + * [Accessibility](#accessibility) + * [Layout](#layout) + * [Authors](#authors) +* [Thanks](#thanks) + + + +## Contributing code to Matrix Please read https://github.com/matrix-org/synapse/blob/master/CONTRIBUTING.md Element Android support can be found in this room: [![Element Android Matrix room #element-android:matrix.org](https://img.shields.io/matrix/element-android:matrix.org.svg?label=%23element-android:matrix.org&logo=matrix&server_fqdn=matrix.org)](https://matrix.to/#/#element-android:matrix.org). -# Specific rules for Matrix Android projects +The rest of the document contains specific rules for Matrix Android projects ## Android Studio settings From 56f3ecc4aff54dc5d6d3176fa539549f90a24a96 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 23 Sep 2022 11:46:40 +0200 Subject: [PATCH 104/187] Disable flaky CantVerifyTest, for the time we are investigating the issue. --- vector-app/src/androidTest/java/im/vector/app/CantVerifyTest.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vector-app/src/androidTest/java/im/vector/app/CantVerifyTest.kt b/vector-app/src/androidTest/java/im/vector/app/CantVerifyTest.kt index 6f9d6cdde9..3f82ce1ef0 100644 --- a/vector-app/src/androidTest/java/im/vector/app/CantVerifyTest.kt +++ b/vector-app/src/androidTest/java/im/vector/app/CantVerifyTest.kt @@ -26,6 +26,7 @@ import androidx.test.filters.LargeTest import com.adevinta.android.barista.internal.viewaction.SleepViewAction import im.vector.app.features.MainActivity import im.vector.app.ui.robot.ElementRobot +import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.rules.RuleChain @@ -34,6 +35,7 @@ import java.util.UUID @RunWith(AndroidJUnit4::class) @LargeTest +@Ignore("Disabled temporarily so that we can unblock other PRs.") class CantVerifyTest { @get:Rule From c7108f3ac37f88c7306b34d804bd0f8183ae2025 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Fri, 23 Sep 2022 13:05:16 +0300 Subject: [PATCH 105/187] Create use case to compute user agent. --- .../network/ComputeUserAgentUseCase.kt | 80 +++++++++++++++++++ .../sdk/internal/network/UserAgentHolder.kt | 64 +-------------- 2 files changed, 84 insertions(+), 60 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ComputeUserAgentUseCase.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ComputeUserAgentUseCase.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ComputeUserAgentUseCase.kt new file mode 100644 index 0000000000..47256a5a94 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ComputeUserAgentUseCase.kt @@ -0,0 +1,80 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.network + +import android.content.Context +import android.os.Build +import org.matrix.android.sdk.BuildConfig +import org.matrix.android.sdk.api.extensions.tryOrNull +import javax.inject.Inject + +class ComputeUserAgentUseCase @Inject constructor() { + + /** + * Create an user agent with the application version. + * Ex: Element/1.5.0 (Xiaomi Mi 9T; Android 11; RKQ1.200826.002; Flavour GooglePlay; MatrixAndroidSdk2 1.5.0) + * + * @param context the context + * @param flavorDescription the flavor description + */ + fun execute(context: Context, flavorDescription: String): String { + val appPackageName = context.applicationContext.packageName + val pm = context.packageManager + + val appName = tryOrNull { pm.getApplicationLabel(pm.getApplicationInfo(appPackageName, 0)).toString() } + ?.takeIf { + it.matches("\\A\\p{ASCII}*\\z".toRegex()) + } + ?: run { + // Use appPackageName instead of appName if appName contains any non-ASCII character + appPackageName + } + val appVersion = tryOrNull { pm.getPackageInfo(context.applicationContext.packageName, 0).versionName } + + if (appName.isNullOrEmpty() || appVersion.isNullOrEmpty()) { + return tryOrNull { System.getProperty("http.agent") } ?: ("Java" + System.getProperty("java.version")) + } + + val deviceManufacturer = Build.MANUFACTURER + val deviceModel = Build.MODEL + val androidVersion = Build.VERSION.RELEASE + val deviceBuildId = Build.DISPLAY + val matrixSdkVersion = BuildConfig.SDK_VERSION + + return buildString { + append(appName) + append("/") + append(appVersion) + append(" (") + append(deviceManufacturer) + append(" ") + append(deviceModel) + append("; ") + append("Android ") + append(androidVersion) + append("; ") + append(deviceBuildId) + append("; ") + append("Flavour ") + append(flavorDescription) + append("; ") + append("MatrixAndroidSdk2 ") + append(matrixSdkVersion) + append(")") + } + } +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt index 58231badb6..9383932cc7 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/UserAgentHolder.kt @@ -17,77 +17,21 @@ package org.matrix.android.sdk.internal.network import android.content.Context -import android.os.Build -import org.matrix.android.sdk.BuildConfig import org.matrix.android.sdk.api.MatrixConfiguration -import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.internal.di.MatrixScope import javax.inject.Inject @MatrixScope internal class UserAgentHolder @Inject constructor( - private val context: Context, - matrixConfiguration: MatrixConfiguration + context: Context, + matrixConfiguration: MatrixConfiguration, + computeUserAgentUseCase: ComputeUserAgentUseCase, ) { var userAgent: String = "" private set init { - setApplicationFlavor(matrixConfiguration.applicationFlavor) - } - - /** - * Create an user agent with the application version. - * Ex: Element/1.5.0 (Xiaomi Mi 9T; Android 11; RKQ1.200826.002; Flavour GooglePlay; MatrixAndroidSdk2 1.5.0) - * - * @param flavorDescription the flavor description - */ - private fun setApplicationFlavor(flavorDescription: String) { - val appPackageName = context.applicationContext.packageName - val pm = context.packageManager - - val appName = tryOrNull { pm.getApplicationLabel(pm.getApplicationInfo(appPackageName, 0)).toString() } - ?.takeIf { - it.matches("\\A\\p{ASCII}*\\z".toRegex()) - } - ?: run { - // Use appPackageName instead of appName if appName contains any non-ASCII character - appPackageName - } - val appVersion = tryOrNull { pm.getPackageInfo(context.applicationContext.packageName, 0).versionName } - - if (appName.isNullOrEmpty() || appVersion.isNullOrEmpty()) { - userAgent = tryOrNull { System.getProperty("http.agent") } ?: ("Java" + System.getProperty("java.version")) - return - } - - val deviceManufacturer = Build.MANUFACTURER - val deviceModel = Build.MODEL - val androidVersion = Build.VERSION.RELEASE - val deviceBuildId = Build.DISPLAY - val matrixSdkVersion = BuildConfig.SDK_VERSION - - userAgent = buildString { - append(appName) - append("/") - append(appVersion) - append(" (") - append(deviceManufacturer) - append(" ") - append(deviceModel) - append("; ") - append("Android ") - append(androidVersion) - append("; ") - append(deviceBuildId) - append("; ") - append("Flavour ") - append(flavorDescription) - append("; ") - append("MatrixAndroidSdk2 ") - append(matrixSdkVersion) - append(")") - } + userAgent = computeUserAgentUseCase.execute(context, matrixConfiguration.applicationFlavor) } } From 2ea357ddc0c62fd5f5d99c1b7fd4a09b41d2361e Mon Sep 17 00:00:00 2001 From: Valere Date: Fri, 23 Sep 2022 12:12:14 +0200 Subject: [PATCH 106/187] Fix new layout flicker/leaks --- .../room/list/home/HomeRoomListViewModel.kt | 80 +++++++++++-------- 1 file changed, 46 insertions(+), 34 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt index 41cf2189c0..63b667a697 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/HomeRoomListViewModel.kt @@ -51,6 +51,8 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.launch +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.query.QueryStringValue import org.matrix.android.sdk.api.query.RoomCategoryFilter @@ -108,12 +110,34 @@ class HomeRoomListViewModel @AssistedInject constructor( private var filteredPagedRoomSummariesLive: UpdatableLivePageResult? = null + private val switchDataSourceMutex = Mutex() + init { observeOrderPreferences() observeInvites() observeRecents() observeFilterTabs() observeRooms() + observeSpaceChanges() + } + + private fun observeSpaceChanges() { + spaceStateHandler.getSelectedSpaceFlow() + .distinctUntilChanged() + .onStart { + emit(spaceStateHandler.getCurrentSpace().toOption()) + } + .onEach { selectedSpaceOption -> + val selectedSpace = selectedSpaceOption.orNull() + filteredPagedRoomSummariesLive?.let { liveResults -> + liveResults.queryParams = liveResults.queryParams.copy( + spaceFilter = selectedSpace?.roomId.toActiveSpaceOrNoFilter() + ) + emitEmptyState() + } + } + .also { roomsFlow = it } + .launchIn(viewModelScope) } private fun observeInvites() { @@ -229,42 +253,30 @@ class HomeRoomListViewModel @AssistedInject constructor( } private fun observeRooms() = viewModelScope.launch { - filteredPagedRoomSummariesLive?.livePagedList?.removeObserver(internalPagedListObserver) + switchDataSourceMutex.withLock { + filteredPagedRoomSummariesLive?.livePagedList?.removeObserver(internalPagedListObserver) - val builder = RoomSummaryQueryParams.Builder().also { - it.memberships = listOf(Membership.JOIN) + val builder = RoomSummaryQueryParams.Builder().also { + it.memberships = listOf(Membership.JOIN) + it.spaceFilter = spaceStateHandler.getCurrentSpace()?.roomId.toActiveSpaceOrNoFilter() + } + + val params = getFilteredQueryParams(currentFilter, builder.build()) + val sortOrder = if (preferencesStore.isAZOrderingEnabledFlow.first()) { + RoomSortOrder.NAME + } else { + RoomSortOrder.ACTIVITY + } + val liveResults = session.roomService().getFilteredPagedRoomSummariesLive( + params, + pagedListConfig, + sortOrder + ).also { + filteredPagedRoomSummariesLive = it + } + + liveResults.livePagedList.observeForever(internalPagedListObserver) } - - val params = getFilteredQueryParams(currentFilter, builder.build()) - val sortOrder = if (preferencesStore.isAZOrderingEnabledFlow.first()) { - RoomSortOrder.NAME - } else { - RoomSortOrder.ACTIVITY - } - val liveResults = session.roomService().getFilteredPagedRoomSummariesLive( - params, - pagedListConfig, - sortOrder - ).also { - filteredPagedRoomSummariesLive = it - } - - spaceStateHandler.getSelectedSpaceFlow() - .distinctUntilChanged() - .onStart { - emit(spaceStateHandler.getCurrentSpace().toOption()) - } - .onEach { selectedSpaceOption -> - val selectedSpace = selectedSpaceOption.orNull() - filteredPagedRoomSummariesLive?.queryParams = liveResults.queryParams.copy( - spaceFilter = selectedSpace?.roomId.toActiveSpaceOrNoFilter() - ) - emitEmptyState() - } - .also { roomsFlow = it } - .launchIn(viewModelScope) - - liveResults.livePagedList.observeForever(internalPagedListObserver) } private fun observeOrderPreferences() { From 97b3b2363ba9f9cdc076d19a2d658ab39ce6470e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 23 Sep 2022 14:09:44 +0200 Subject: [PATCH 107/187] Disable not passing VoiceRecorderLTests, for the time we are investigating the issue. --- .../java/im/vector/app/features/voice/VoiceRecorderLTests.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderLTests.kt b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderLTests.kt index 1687ee4388..3d7ac3971c 100644 --- a/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderLTests.kt +++ b/vector/src/androidTest/java/im/vector/app/features/voice/VoiceRecorderLTests.kt @@ -26,10 +26,12 @@ import org.amshove.kluent.shouldBeNull import org.amshove.kluent.shouldExist import org.amshove.kluent.shouldNotBeNull import org.amshove.kluent.shouldNotExist +import org.junit.Ignore import org.junit.Rule import org.junit.Test import java.io.File +@Ignore("Disabled temporarily so that we can unblock other PRs.") class VoiceRecorderLTests { @get:Rule From 42983f5ce458b2ef515389b4ca0d259bc42214b0 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Fri, 23 Sep 2022 15:55:02 +0300 Subject: [PATCH 108/187] Write unit test for computing user agent user case. --- .../network/ComputeUserAgentUseCase.kt | 12 +- .../network/ComputeUserAgentUseCaseTest.kt | 149 ++++++++++++++++++ 2 files changed, 155 insertions(+), 6 deletions(-) create mode 100644 matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/network/ComputeUserAgentUseCaseTest.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ComputeUserAgentUseCase.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ComputeUserAgentUseCase.kt index 47256a5a94..64696ca298 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ComputeUserAgentUseCase.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/ComputeUserAgentUseCase.kt @@ -40,14 +40,10 @@ class ComputeUserAgentUseCase @Inject constructor() { it.matches("\\A\\p{ASCII}*\\z".toRegex()) } ?: run { - // Use appPackageName instead of appName if appName contains any non-ASCII character + // Use appPackageName instead of appName if appName is null or contains any non-ASCII character appPackageName } - val appVersion = tryOrNull { pm.getPackageInfo(context.applicationContext.packageName, 0).versionName } - - if (appName.isNullOrEmpty() || appVersion.isNullOrEmpty()) { - return tryOrNull { System.getProperty("http.agent") } ?: ("Java" + System.getProperty("java.version")) - } + val appVersion = tryOrNull { pm.getPackageInfo(context.applicationContext.packageName, 0).versionName } ?: FALLBACK_APP_VERSION val deviceManufacturer = Build.MANUFACTURER val deviceModel = Build.MODEL @@ -77,4 +73,8 @@ class ComputeUserAgentUseCase @Inject constructor() { append(")") } } + + companion object { + const val FALLBACK_APP_VERSION = "0.0.0" + } } diff --git a/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/network/ComputeUserAgentUseCaseTest.kt b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/network/ComputeUserAgentUseCaseTest.kt new file mode 100644 index 0000000000..77f432a70a --- /dev/null +++ b/matrix-sdk-android/src/test/java/org/matrix/android/sdk/internal/network/ComputeUserAgentUseCaseTest.kt @@ -0,0 +1,149 @@ +/* + * Copyright 2022 The Matrix.org Foundation C.I.C. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.matrix.android.sdk.internal.network + +import android.content.Context +import android.content.pm.ApplicationInfo +import android.content.pm.PackageInfo +import android.content.pm.PackageManager +import android.os.Build +import io.mockk.every +import io.mockk.mockk +import org.amshove.kluent.shouldBeEqualTo +import org.junit.Before +import org.junit.Test +import org.matrix.android.sdk.BuildConfig +import java.lang.Exception + +private const val A_PACKAGE_NAME = "org.matrix.sdk" +private const val AN_APP_NAME = "Element" +private const val A_NON_ASCII_APP_NAME = "Élement" +private const val AN_APP_VERSION = "1.5.1" +private const val A_FLAVOUR = "GooglePlay" + +class ComputeUserAgentUseCaseTest { + + private val context = mockk() + private val packageManager = mockk() + private val applicationInfo = mockk() + private val packageInfo = mockk() + + private val computeUserAgentUseCase = ComputeUserAgentUseCase() + + @Before + fun setUp() { + every { context.applicationContext } returns context + every { context.packageName } returns A_PACKAGE_NAME + every { context.packageManager } returns packageManager + every { packageManager.getApplicationInfo(any(), any()) } returns applicationInfo + every { packageManager.getPackageInfo(any(), any()) } returns packageInfo + } + + @Test + fun `given a non-null app name and app version when computing user agent then returns expected user agent`() { + // Given + givenAppName(AN_APP_NAME) + givenAppVersion(AN_APP_VERSION) + + // When + val result = computeUserAgentUseCase.execute(context, A_FLAVOUR) + + // Then + val expectedUserAgent = constructExpectedUserAgent(AN_APP_NAME, AN_APP_VERSION) + result shouldBeEqualTo expectedUserAgent + } + + @Test + fun `given a null app name when computing user agent then returns user agent with package name instead of app name`() { + // Given + givenAppName(null) + givenAppVersion(AN_APP_VERSION) + + // When + val result = computeUserAgentUseCase.execute(context, A_FLAVOUR) + + // Then + val expectedUserAgent = constructExpectedUserAgent(A_PACKAGE_NAME, AN_APP_VERSION) + result shouldBeEqualTo expectedUserAgent + } + + @Test + fun `given a non-ascii app name when computing user agent then returns user agent with package name instead of app name`() { + // Given + givenAppName(A_NON_ASCII_APP_NAME) + givenAppVersion(AN_APP_VERSION) + + // When + val result = computeUserAgentUseCase.execute(context, A_FLAVOUR) + + // Then + val expectedUserAgent = constructExpectedUserAgent(A_PACKAGE_NAME, AN_APP_VERSION) + result shouldBeEqualTo expectedUserAgent + } + + @Test + fun `given a null app version when computing user agent then returns user agent with a fallback app version`() { + // Given + givenAppName(AN_APP_NAME) + givenAppVersion(null) + + // When + val result = computeUserAgentUseCase.execute(context, A_FLAVOUR) + + // Then + val expectedUserAgent = constructExpectedUserAgent(AN_APP_NAME, ComputeUserAgentUseCase.FALLBACK_APP_VERSION) + result shouldBeEqualTo expectedUserAgent + } + + private fun constructExpectedUserAgent(appName: String, appVersion: String): String { + return buildString { + append(appName) + append("/") + append(appVersion) + append(" (") + append(Build.MANUFACTURER) + append(" ") + append(Build.MODEL) + append("; ") + append("Android ") + append(Build.VERSION.RELEASE) + append("; ") + append(Build.DISPLAY) + append("; ") + append("Flavour ") + append(A_FLAVOUR) + append("; ") + append("MatrixAndroidSdk2 ") + append(BuildConfig.SDK_VERSION) + append(")") + } + } + + private fun givenAppName(deviceName: String?) { + if (deviceName == null) { + every { packageManager.getApplicationLabel(any()) } throws Exception("Cannot retrieve application name") + } else if (!deviceName.matches("\\A\\p{ASCII}*\\z".toRegex())) { + every { packageManager.getApplicationLabel(any()) } returns A_PACKAGE_NAME + } else { + every { packageManager.getApplicationLabel(any()) } returns deviceName + } + } + + private fun givenAppVersion(appVersion: String?) { + packageInfo.versionName = appVersion + } +} From 6cba51eff3de5220e12406b8260f706e8befaaf8 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 23 Sep 2022 15:09:17 +0200 Subject: [PATCH 109/187] Update changelog 1.5.0 for fastlane --- fastlane/metadata/android/en-US/changelogs/40105000.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fastlane/metadata/android/en-US/changelogs/40105000.txt b/fastlane/metadata/android/en-US/changelogs/40105000.txt index 1bfa2b3dea..e86519e6e9 100644 --- a/fastlane/metadata/android/en-US/changelogs/40105000.txt +++ b/fastlane/metadata/android/en-US/changelogs/40105000.txt @@ -1,2 +1,2 @@ -Main changes in this version: New App Layout and Deferred DM enabled by default. -Full changelog: https://github.com/vector-im/element-android/releases \ No newline at end of file +Main changes in this version: Deferred DM enabled by default. +Full changelog: https://github.com/vector-im/element-android/releases From 892fd4445c4bfe2600643746d0547bc17a713373 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 21 Sep 2022 14:55:37 +0200 Subject: [PATCH 110/187] Mutualize pending auth handling --- .../app/features/auth/PendingAuthHandler.kt | 69 +++++++++++++++++++ .../recover/BootstrapSharedViewModel.kt | 37 +++------- .../DeactivateAccountViewModel.kt | 45 ++---------- .../CrossSigningSettingsViewModel.kt | 40 ++--------- .../settings/devices/DevicesViewModel.kt | 48 ++----------- .../threepids/ThreePidsSettingsViewModel.kt | 46 ++----------- 6 files changed, 106 insertions(+), 179 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/auth/PendingAuthHandler.kt diff --git a/vector/src/main/java/im/vector/app/features/auth/PendingAuthHandler.kt b/vector/src/main/java/im/vector/app/features/auth/PendingAuthHandler.kt new file mode 100644 index 0000000000..f4573a54a7 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/auth/PendingAuthHandler.kt @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.auth + +import im.vector.app.core.di.ActiveSessionHolder +import org.matrix.android.sdk.api.Matrix +import org.matrix.android.sdk.api.auth.UIABaseAuth +import org.matrix.android.sdk.api.auth.UserPasswordAuth +import org.matrix.android.sdk.api.util.fromBase64 +import timber.log.Timber +import javax.inject.Inject +import kotlin.coroutines.Continuation +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException + +class PendingAuthHandler @Inject constructor( + private val matrix: Matrix, + private val activeSessionHolder: ActiveSessionHolder, +) { + + var uiaContinuation: Continuation? = null + var pendingAuth: UIABaseAuth? = null + + fun ssoAuthDone() { + Timber.d("ssoAuthDone $pendingAuth , continuation: $uiaContinuation") + pendingAuth?.let { + uiaContinuation?.resume(it) + } ?: run { + uiaContinuation?.resumeWithException(IllegalArgumentException()) + } + } + + fun passwordAuthDone(password: String) { + Timber.d("passwordAuthDone") + val decryptedPass = matrix.secureStorageService() + .loadSecureSecret( + inputStream = password.fromBase64().inputStream(), + keyAlias = ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS + ) + uiaContinuation?.resume( + UserPasswordAuth( + session = pendingAuth?.session, + password = decryptedPass, + user = activeSessionHolder.getActiveSession().myUserId + ) + ) + } + + fun reAuthCancelled() { + Timber.d("reAuthCancelled") + uiaContinuation?.resumeWithException(Exception()) + uiaContinuation = null + pendingAuth = null + } +} diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt index 658fad9284..bab112cd66 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapSharedViewModel.kt @@ -32,14 +32,13 @@ import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.platform.WaitingViewData import im.vector.app.core.resources.StringProvider -import im.vector.app.features.auth.ReAuthActivity +import im.vector.app.features.auth.PendingAuthHandler import im.vector.app.features.raw.wellknown.SecureBackupMethod import im.vector.app.features.raw.wellknown.getElementWellknown import im.vector.app.features.raw.wellknown.isSecureBackupRequired import im.vector.app.features.raw.wellknown.secureBackupMethod import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserPasswordAuth @@ -57,10 +56,8 @@ import org.matrix.android.sdk.api.session.crypto.keysbackup.toKeysVersionResult import org.matrix.android.sdk.api.session.securestorage.RawBytesKeySpec import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth import org.matrix.android.sdk.api.util.awaitCallback -import org.matrix.android.sdk.api.util.fromBase64 import java.io.OutputStream import kotlin.coroutines.Continuation -import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException class BootstrapSharedViewModel @AssistedInject constructor( @@ -71,7 +68,7 @@ class BootstrapSharedViewModel @AssistedInject constructor( private val rawService: RawService, private val bootstrapTask: BootstrapCrossSigningTask, private val migrationTask: BackupToQuadSMigrationTask, - private val matrix: Matrix, + private val pendingAuthHandler: PendingAuthHandler, ) : VectorViewModel(initialState) { private var doesKeyBackupExist: Boolean = false @@ -85,11 +82,6 @@ class BootstrapSharedViewModel @AssistedInject constructor( companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() -// private var _pendingSession: String? = null - - var uiaContinuation: Continuation? = null - var pendingAuth: UIABaseAuth? = null - init { setState { @@ -272,21 +264,10 @@ class BootstrapSharedViewModel @AssistedInject constructor( is BootstrapActions.DoMigrateWithRecoveryKey -> { startMigrationFlow(state.step, null, action.recoveryKey) } - BootstrapActions.SsoAuthDone -> { - uiaContinuation?.resume(DefaultBaseAuth(session = pendingAuth?.session ?: "")) - } - is BootstrapActions.PasswordAuthDone -> { - val decryptedPass = matrix.secureStorageService() - .loadSecureSecret(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) - uiaContinuation?.resume( - UserPasswordAuth( - session = pendingAuth?.session, - password = decryptedPass, - user = session.myUserId - ) - ) - } + BootstrapActions.SsoAuthDone -> pendingAuthHandler.ssoAuthDone() + is BootstrapActions.PasswordAuthDone -> pendingAuthHandler.passwordAuthDone(action.password) BootstrapActions.ReAuthCancelled -> { + pendingAuthHandler.reAuthCancelled() setState { copy(step = BootstrapStep.AccountReAuth(stringProvider.getString(R.string.authentication_error))) } @@ -402,13 +383,13 @@ class BootstrapSharedViewModel @AssistedInject constructor( override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation) { when (flowResponse.nextUncompletedStage()) { LoginFlowTypes.PASSWORD -> { - pendingAuth = UserPasswordAuth( + pendingAuthHandler.pendingAuth = UserPasswordAuth( // Note that _pendingSession may or may not be null, this is OK, it will be managed by the task session = flowResponse.session, user = session.myUserId, password = null ) - uiaContinuation = promise + pendingAuthHandler.uiaContinuation = promise setState { copy( step = BootstrapStep.AccountReAuth() @@ -417,8 +398,8 @@ class BootstrapSharedViewModel @AssistedInject constructor( _viewEvents.post(BootstrapViewEvents.RequestReAuth(flowResponse, errCode)) } LoginFlowTypes.SSO -> { - pendingAuth = DefaultBaseAuth(flowResponse.session) - uiaContinuation = promise + pendingAuthHandler.pendingAuth = DefaultBaseAuth(flowResponse.session) + pendingAuthHandler.uiaContinuation = promise setState { copy( step = BootstrapStep.AccountReAuth() diff --git a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt index a652a62a6c..c5d71db6da 100644 --- a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt @@ -23,22 +23,15 @@ import dagger.assisted.AssistedInject import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel -import im.vector.app.features.auth.ReAuthActivity +import im.vector.app.features.auth.PendingAuthHandler import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor -import org.matrix.android.sdk.api.auth.UserPasswordAuth import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.failure.isInvalidUIAAuth import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth -import org.matrix.android.sdk.api.session.uia.exceptions.UiaCancelledException -import org.matrix.android.sdk.api.util.fromBase64 -import timber.log.Timber import kotlin.coroutines.Continuation -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException data class DeactivateAccountViewState( val dummy: Boolean = false @@ -47,7 +40,7 @@ data class DeactivateAccountViewState( class DeactivateAccountViewModel @AssistedInject constructor( @Assisted private val initialState: DeactivateAccountViewState, private val session: Session, - private val matrix: Matrix, + private val pendingAuthHandler: PendingAuthHandler, ) : VectorViewModel(initialState) { @@ -56,39 +49,15 @@ class DeactivateAccountViewModel @AssistedInject constructor( override fun create(initialState: DeactivateAccountViewState): DeactivateAccountViewModel } - var uiaContinuation: Continuation? = null - var pendingAuth: UIABaseAuth? = null - override fun handle(action: DeactivateAccountAction) { when (action) { is DeactivateAccountAction.DeactivateAccount -> handleDeactivateAccount(action) - DeactivateAccountAction.SsoAuthDone -> { - Timber.d("## UIA - FallBack success") - _viewEvents.post(DeactivateAccountViewEvents.Loading()) - if (pendingAuth != null) { - uiaContinuation?.resume(pendingAuth!!) - } else { - uiaContinuation?.resumeWithException(IllegalArgumentException()) - } - } + DeactivateAccountAction.SsoAuthDone -> pendingAuthHandler.ssoAuthDone() is DeactivateAccountAction.PasswordAuthDone -> { _viewEvents.post(DeactivateAccountViewEvents.Loading()) - val decryptedPass = matrix.secureStorageService() - .loadSecureSecret(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) - uiaContinuation?.resume( - UserPasswordAuth( - session = pendingAuth?.session, - password = decryptedPass, - user = session.myUserId - ) - ) - } - DeactivateAccountAction.ReAuthCancelled -> { - Timber.d("## UIA - Reauth cancelled") - uiaContinuation?.resumeWithException(UiaCancelledException()) - uiaContinuation = null - pendingAuth = null + pendingAuthHandler.passwordAuthDone(action.password) } + DeactivateAccountAction.ReAuthCancelled -> pendingAuthHandler.reAuthCancelled() } } @@ -102,8 +71,8 @@ class DeactivateAccountViewModel @AssistedInject constructor( object : UserInteractiveAuthInterceptor { override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation) { _viewEvents.post(DeactivateAccountViewEvents.RequestReAuth(flowResponse, errCode)) - pendingAuth = DefaultBaseAuth(session = flowResponse.session) - uiaContinuation = promise + pendingAuthHandler.pendingAuth = DefaultBaseAuth(session = flowResponse.session) + pendingAuthHandler.uiaContinuation = promise } } ) diff --git a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt index 87eaa01e2b..20b96e0029 100644 --- a/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/crosssigning/CrossSigningSettingsViewModel.kt @@ -24,12 +24,11 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider -import im.vector.app.features.auth.ReAuthActivity +import im.vector.app.features.auth.PendingAuthHandler import im.vector.app.features.login.ReAuthHelper import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor import org.matrix.android.sdk.api.auth.UserPasswordAuth @@ -40,19 +39,17 @@ import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.crypto.crosssigning.isVerified import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth import org.matrix.android.sdk.api.util.awaitCallback -import org.matrix.android.sdk.api.util.fromBase64 import org.matrix.android.sdk.flow.flow import timber.log.Timber import kotlin.coroutines.Continuation import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException class CrossSigningSettingsViewModel @AssistedInject constructor( @Assisted private val initialState: CrossSigningSettingsViewState, private val session: Session, private val reAuthHelper: ReAuthHelper, private val stringProvider: StringProvider, - private val matrix: Matrix, + private val pendingAuthHandler: PendingAuthHandler, ) : VectorViewModel(initialState) { init { @@ -77,9 +74,6 @@ class CrossSigningSettingsViewModel @AssistedInject constructor( } } - var uiaContinuation: Continuation? = null - var pendingAuth: UIABaseAuth? = null - @AssistedFactory interface Factory : MavericksAssistedViewModelFactory { override fun create(initialState: CrossSigningSettingsViewState): CrossSigningSettingsViewModel @@ -110,8 +104,8 @@ class CrossSigningSettingsViewModel @AssistedInject constructor( } else { Timber.d("## UIA : initializeCrossSigning UIA > start reauth activity") _viewEvents.post(CrossSigningSettingsViewEvents.RequestReAuth(flowResponse, errCode)) - pendingAuth = DefaultBaseAuth(session = flowResponse.session) - uiaContinuation = promise + pendingAuthHandler.pendingAuth = DefaultBaseAuth(session = flowResponse.session) + pendingAuthHandler.uiaContinuation = promise } } }, it @@ -125,31 +119,11 @@ class CrossSigningSettingsViewModel @AssistedInject constructor( } Unit } - is CrossSigningSettingsAction.SsoAuthDone -> { - Timber.d("## UIA - FallBack success") - if (pendingAuth != null) { - uiaContinuation?.resume(pendingAuth!!) - } else { - uiaContinuation?.resumeWithException(IllegalArgumentException()) - } - } - is CrossSigningSettingsAction.PasswordAuthDone -> { - val decryptedPass = matrix.secureStorageService() - .loadSecureSecret(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) - uiaContinuation?.resume( - UserPasswordAuth( - session = pendingAuth?.session, - password = decryptedPass, - user = session.myUserId - ) - ) - } + is CrossSigningSettingsAction.SsoAuthDone -> pendingAuthHandler.ssoAuthDone() + is CrossSigningSettingsAction.PasswordAuthDone -> pendingAuthHandler.passwordAuthDone(action.password) CrossSigningSettingsAction.ReAuthCancelled -> { - Timber.d("## UIA - Reauth cancelled") _viewEvents.post(CrossSigningSettingsViewEvents.HideModalWaitingView) - uiaContinuation?.resumeWithException(Exception()) - uiaContinuation = null - pendingAuth = null + pendingAuthHandler.reAuthCancelled() } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt index d30d6ee270..67b41ea5aa 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/DevicesViewModel.kt @@ -32,7 +32,7 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.PublishDataSource -import im.vector.app.features.auth.ReAuthActivity +import im.vector.app.features.auth.PendingAuthHandler import im.vector.app.features.login.ReAuthHelper import im.vector.app.features.settings.devices.v2.list.CheckIfSessionIsInactiveUseCase import im.vector.app.features.settings.devices.v2.verification.GetEncryptionTrustLevelForDeviceUseCase @@ -45,7 +45,6 @@ import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.sample import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.MatrixCallback import org.matrix.android.sdk.api.NoOpMatrixCallback import org.matrix.android.sdk.api.auth.UIABaseAuth @@ -67,13 +66,11 @@ import org.matrix.android.sdk.api.session.crypto.verification.VerificationTransa import org.matrix.android.sdk.api.session.crypto.verification.VerificationTxState import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth import org.matrix.android.sdk.api.util.awaitCallback -import org.matrix.android.sdk.api.util.fromBase64 import org.matrix.android.sdk.flow.flow import timber.log.Timber import javax.net.ssl.HttpsURLConnection import kotlin.coroutines.Continuation import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException data class DevicesViewState( val myDeviceId: String = "", @@ -100,15 +97,12 @@ class DevicesViewModel @AssistedInject constructor( private val session: Session, private val reAuthHelper: ReAuthHelper, private val stringProvider: StringProvider, - private val matrix: Matrix, + private val pendingAuthHandler: PendingAuthHandler, private val checkIfSessionIsInactiveUseCase: CheckIfSessionIsInactiveUseCase, getCurrentSessionCrossSigningInfoUseCase: GetCurrentSessionCrossSigningInfoUseCase, private val getEncryptionTrustLevelForDeviceUseCase: GetEncryptionTrustLevelForDeviceUseCase, ) : VectorViewModel(initialState), VerificationService.Listener { - var uiaContinuation: Continuation? = null - var pendingAuth: UIABaseAuth? = null - @AssistedFactory interface Factory : MavericksAssistedViewModelFactory { override fun create(initialState: DevicesViewState): DevicesViewModel @@ -232,37 +226,9 @@ class DevicesViewModel @AssistedInject constructor( is DevicesAction.CompleteSecurity -> handleCompleteSecurity() is DevicesAction.MarkAsManuallyVerified -> handleVerifyManually(action) is DevicesAction.VerifyMyDeviceManually -> handleShowDeviceCryptoInfo(action) - is DevicesAction.SsoAuthDone -> { - // we should use token based auth - // _viewEvents.post(CrossSigningSettingsViewEvents.ShowModalWaitingView(null)) - // will release the interactive auth interceptor - Timber.d("## UIA - FallBack success $pendingAuth , continuation: $uiaContinuation") - if (pendingAuth != null) { - uiaContinuation?.resume(pendingAuth!!) - } else { - uiaContinuation?.resumeWithException(IllegalArgumentException()) - } - Unit - } - is DevicesAction.PasswordAuthDone -> { - val decryptedPass = matrix.secureStorageService() - .loadSecureSecret(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) - uiaContinuation?.resume( - UserPasswordAuth( - session = pendingAuth?.session, - password = decryptedPass, - user = session.myUserId - ) - ) - Unit - } - DevicesAction.ReAuthCancelled -> { - Timber.d("## UIA - Reauth cancelled") -// _viewEvents.post(DevicesViewEvents.Loading) - uiaContinuation?.resumeWithException(Exception()) - uiaContinuation = null - pendingAuth = null - } + is DevicesAction.SsoAuthDone -> pendingAuthHandler.ssoAuthDone() + is DevicesAction.PasswordAuthDone -> pendingAuthHandler.passwordAuthDone(action.password) + DevicesAction.ReAuthCancelled -> pendingAuthHandler.reAuthCancelled() DevicesAction.ResetSecurity -> _viewEvents.post(DevicesViewEvents.PromptResetSecrets) } } @@ -371,8 +337,8 @@ class DevicesViewModel @AssistedInject constructor( } else { Timber.d("## UIA : deleteDevice UIA > start reauth activity") _viewEvents.post(DevicesViewEvents.RequestReAuth(flowResponse, errCode)) - pendingAuth = DefaultBaseAuth(session = flowResponse.session) - uiaContinuation = promise + pendingAuthHandler.pendingAuth = DefaultBaseAuth(session = flowResponse.session) + pendingAuthHandler.uiaContinuation = promise } } }, it) diff --git a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt index d80553b0ed..249df0007f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/threepids/ThreePidsSettingsViewModel.kt @@ -28,33 +28,26 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.ReadOnceTrue -import im.vector.app.features.auth.ReAuthActivity +import im.vector.app.features.auth.PendingAuthHandler import kotlinx.coroutines.launch -import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserInteractiveAuthInterceptor -import org.matrix.android.sdk.api.auth.UserPasswordAuth import org.matrix.android.sdk.api.auth.registration.RegistrationFlowResponse import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.uia.DefaultBaseAuth -import org.matrix.android.sdk.api.util.fromBase64 import org.matrix.android.sdk.flow.flow -import timber.log.Timber import kotlin.coroutines.Continuation -import kotlin.coroutines.resume -import kotlin.coroutines.resumeWithException class ThreePidsSettingsViewModel @AssistedInject constructor( @Assisted initialState: ThreePidsSettingsViewState, private val session: Session, private val stringProvider: StringProvider, - private val matrix: Matrix, + private val pendingAuthHandler: PendingAuthHandler, ) : VectorViewModel(initialState) { // UIA session private var pendingThreePid: ThreePid? = null -// private var pendingSession: String? = null private suspend fun loadingSuspendable(block: suspend () -> Unit) { runCatching { block() } @@ -126,42 +119,17 @@ class ThreePidsSettingsViewModel @AssistedInject constructor( is ThreePidsSettingsAction.CancelThreePid -> handleCancelThreePid(action) is ThreePidsSettingsAction.DeleteThreePid -> handleDeleteThreePid(action) is ThreePidsSettingsAction.ChangeUiState -> handleChangeUiState(action) - ThreePidsSettingsAction.SsoAuthDone -> { - Timber.d("## UIA - FallBack success") - if (pendingAuth != null) { - uiaContinuation?.resume(pendingAuth!!) - } else { - uiaContinuation?.resumeWithException(IllegalArgumentException()) - } - } - is ThreePidsSettingsAction.PasswordAuthDone -> { - val decryptedPass = matrix.secureStorageService() - .loadSecureSecret(action.password.fromBase64().inputStream(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) - uiaContinuation?.resume( - UserPasswordAuth( - session = pendingAuth?.session, - password = decryptedPass, - user = session.myUserId - ) - ) - } - ThreePidsSettingsAction.ReAuthCancelled -> { - Timber.d("## UIA - Reauth cancelled") - uiaContinuation?.resumeWithException(Exception()) - uiaContinuation = null - pendingAuth = null - } + ThreePidsSettingsAction.SsoAuthDone -> pendingAuthHandler.ssoAuthDone() + is ThreePidsSettingsAction.PasswordAuthDone -> pendingAuthHandler.passwordAuthDone(action.password) + ThreePidsSettingsAction.ReAuthCancelled -> pendingAuthHandler.reAuthCancelled() } } - var uiaContinuation: Continuation? = null - var pendingAuth: UIABaseAuth? = null - private val uiaInterceptor = object : UserInteractiveAuthInterceptor { override fun performStage(flowResponse: RegistrationFlowResponse, errCode: String?, promise: Continuation) { _viewEvents.post(ThreePidsSettingsViewEvents.RequestReAuth(flowResponse, errCode)) - pendingAuth = DefaultBaseAuth(session = flowResponse.session) - uiaContinuation = promise + pendingAuthHandler.pendingAuth = DefaultBaseAuth(session = flowResponse.session) + pendingAuthHandler.uiaContinuation = promise } } From 0cd352ccba982da346f8ec7278dea793186d8d9d Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 21 Sep 2022 15:14:15 +0200 Subject: [PATCH 111/187] Adding changelog entry --- changelog.d/7193.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7193.misc diff --git a/changelog.d/7193.misc b/changelog.d/7193.misc new file mode 100644 index 0000000000..efa0f594ae --- /dev/null +++ b/changelog.d/7193.misc @@ -0,0 +1 @@ +Mutualize the pending auth handling From 0d7d841d7391fd1aed4df7e8ac5e12a6526236b9 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 21 Sep 2022 17:36:51 +0200 Subject: [PATCH 112/187] Adding unit tests --- .../features/auth/PendingAuthHandlerTest.kt | 143 ++++++++++++++++++ .../im/vector/app/test/fakes/FakeMatrix.kt | 32 ++++ .../test/fakes/FakeSecureStorageService.kt | 28 ++++ 3 files changed, 203 insertions(+) create mode 100644 vector/src/test/java/im/vector/app/features/auth/PendingAuthHandlerTest.kt create mode 100644 vector/src/test/java/im/vector/app/test/fakes/FakeMatrix.kt create mode 100644 vector/src/test/java/im/vector/app/test/fakes/FakeSecureStorageService.kt diff --git a/vector/src/test/java/im/vector/app/features/auth/PendingAuthHandlerTest.kt b/vector/src/test/java/im/vector/app/features/auth/PendingAuthHandlerTest.kt new file mode 100644 index 0000000000..bc0f6495ae --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/auth/PendingAuthHandlerTest.kt @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.auth + +import android.util.Base64 +import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeMatrix +import io.mockk.every +import io.mockk.just +import io.mockk.mockk +import io.mockk.mockkStatic +import io.mockk.runs +import io.mockk.unmockkAll +import io.mockk.verify +import org.amshove.kluent.shouldBe +import org.junit.After +import org.junit.Before +import org.junit.Ignore +import org.junit.Test +import org.matrix.android.sdk.api.auth.UIABaseAuth +import org.matrix.android.sdk.api.auth.UserPasswordAuth +import kotlin.coroutines.Continuation +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException + +private const val A_PASSWORD = "a-password" +private const val A_SESSION_ID = "session-id" + +class PendingAuthHandlerTest { + + private val fakeMatrix = FakeMatrix() + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + + private val pendingAuthHandler = PendingAuthHandler( + matrix = fakeMatrix.instance, + activeSessionHolder = fakeActiveSessionHolder.instance, + ) + + @Before + fun setUp() { + mockkStatic(Base64::class) + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `given a pending auth and continuation when SSO auth is done then continuation is resumed with pending auth`() { + // Given + val pendingAuth = mockk() + val continuation = mockk>() + every { continuation.resume(any()) } just runs + pendingAuthHandler.pendingAuth = pendingAuth + pendingAuthHandler.uiaContinuation = continuation + + // When + pendingAuthHandler.ssoAuthDone() + + // Then + verify { continuation.resume(pendingAuth) } + } + + @Test + @Ignore("Ignored due because of problem to mock the inline method continuation.resumeWithException") + fun `given missing pending auth and continuation when SSO auth is done then continuation is resumed with error`() { + // Given + val pendingAuth = null + val continuation = mockk>() + every { continuation.resumeWithException(any()) } just runs + pendingAuthHandler.pendingAuth = pendingAuth + pendingAuthHandler.uiaContinuation = continuation + + // When + pendingAuthHandler.ssoAuthDone() + + // Then + verify { continuation.resumeWithException(match { it is IllegalArgumentException })} + } + + @Test + fun `given a password, pending auth and continuation when password auth is done then continuation is resumed with correct auth`() { + // Given + val pendingAuth = mockk() + every { pendingAuth.session } returns A_SESSION_ID + val continuation = mockk>() + every { continuation.resume(any()) } just runs + pendingAuthHandler.pendingAuth = pendingAuth + pendingAuthHandler.uiaContinuation = continuation + val decryptedPwd = "decrypted-pwd" + val decodedPwd = byteArrayOf() + every { Base64.decode(A_PASSWORD, any()) } returns decodedPwd + fakeMatrix.fakeSecureStorageService.givenLoadSecureSecretReturns(decryptedPwd) + val expectedAuth = UserPasswordAuth( + session = A_SESSION_ID, + password = decryptedPwd, + user = fakeActiveSessionHolder.fakeSession.myUserId + ) + + // When + pendingAuthHandler.passwordAuthDone(A_PASSWORD) + + // Then + verify { + fakeMatrix.fakeSecureStorageService.loadSecureSecret(any(), ReAuthActivity.DEFAULT_RESULT_KEYSTORE_ALIAS) + continuation.resume(expectedAuth) + } + } + + @Test + @Ignore("Ignored because of problem to mock the inline method continuation.resumeWithException") + fun `given pending auth and continuation when reAuth is cancelled then pending auth and continuation are reset`() { + // Given + val pendingAuth = mockk() + val continuation = mockk>() + every { continuation.resumeWithException(any()) } just runs + pendingAuthHandler.pendingAuth = pendingAuth + pendingAuthHandler.uiaContinuation = continuation + + // When + pendingAuthHandler.reAuthCancelled() + + // Then + pendingAuthHandler.pendingAuth shouldBe null + pendingAuthHandler.uiaContinuation shouldBe null + verify { continuation.resumeWithException(match { it is Exception })} + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeMatrix.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeMatrix.kt new file mode 100644 index 0000000000..d4761a14af --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeMatrix.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.test.fakes + +import io.mockk.every +import io.mockk.mockk +import org.matrix.android.sdk.api.Matrix + +class FakeMatrix( + val fakeSecureStorageService: FakeSecureStorageService = FakeSecureStorageService(), +) { + + val instance = mockk() + + init { + every { instance.secureStorageService() } returns fakeSecureStorageService + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeSecureStorageService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeSecureStorageService.kt new file mode 100644 index 0000000000..8055304172 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeSecureStorageService.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.test.fakes + +import io.mockk.every +import io.mockk.mockk +import org.matrix.android.sdk.api.securestorage.SecureStorageService + +class FakeSecureStorageService : SecureStorageService by mockk() { + + fun givenLoadSecureSecretReturns(value: T?) { + every { loadSecureSecret(any(), any()) } returns value + } +} From 99c2088d0e23571cac2ec9ff048648d0e005a909 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 22 Sep 2022 10:31:37 +0200 Subject: [PATCH 113/187] Using UiaCancelledException on reAuth cancellation --- .../java/im/vector/app/features/auth/PendingAuthHandler.kt | 3 ++- .../im/vector/app/features/auth/PendingAuthHandlerTest.kt | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/auth/PendingAuthHandler.kt b/vector/src/main/java/im/vector/app/features/auth/PendingAuthHandler.kt index f4573a54a7..b986090e50 100644 --- a/vector/src/main/java/im/vector/app/features/auth/PendingAuthHandler.kt +++ b/vector/src/main/java/im/vector/app/features/auth/PendingAuthHandler.kt @@ -20,6 +20,7 @@ import im.vector.app.core.di.ActiveSessionHolder import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserPasswordAuth +import org.matrix.android.sdk.api.session.uia.exceptions.UiaCancelledException import org.matrix.android.sdk.api.util.fromBase64 import timber.log.Timber import javax.inject.Inject @@ -62,7 +63,7 @@ class PendingAuthHandler @Inject constructor( fun reAuthCancelled() { Timber.d("reAuthCancelled") - uiaContinuation?.resumeWithException(Exception()) + uiaContinuation?.resumeWithException(UiaCancelledException()) uiaContinuation = null pendingAuth = null } diff --git a/vector/src/test/java/im/vector/app/features/auth/PendingAuthHandlerTest.kt b/vector/src/test/java/im/vector/app/features/auth/PendingAuthHandlerTest.kt index bc0f6495ae..a3b75aa7f4 100644 --- a/vector/src/test/java/im/vector/app/features/auth/PendingAuthHandlerTest.kt +++ b/vector/src/test/java/im/vector/app/features/auth/PendingAuthHandlerTest.kt @@ -33,6 +33,7 @@ import org.junit.Ignore import org.junit.Test import org.matrix.android.sdk.api.auth.UIABaseAuth import org.matrix.android.sdk.api.auth.UserPasswordAuth +import org.matrix.android.sdk.api.session.uia.exceptions.UiaCancelledException import kotlin.coroutines.Continuation import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException @@ -90,7 +91,7 @@ class PendingAuthHandlerTest { pendingAuthHandler.ssoAuthDone() // Then - verify { continuation.resumeWithException(match { it is IllegalArgumentException })} + verify { continuation.resumeWithException(match { it is IllegalArgumentException }) } } @Test @@ -138,6 +139,6 @@ class PendingAuthHandlerTest { // Then pendingAuthHandler.pendingAuth shouldBe null pendingAuthHandler.uiaContinuation shouldBe null - verify { continuation.resumeWithException(match { it is Exception })} + verify { continuation.resumeWithException(match { it is UiaCancelledException }) } } } From 854a604fbe891114d9b2ef8764221cbd0a25cda0 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 22 Sep 2022 10:32:03 +0200 Subject: [PATCH 114/187] Fix missing loading ViewEvent --- .../account/deactivation/DeactivateAccountViewModel.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt index c5d71db6da..dcc584e6c3 100644 --- a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountViewModel.kt @@ -52,7 +52,10 @@ class DeactivateAccountViewModel @AssistedInject constructor( override fun handle(action: DeactivateAccountAction) { when (action) { is DeactivateAccountAction.DeactivateAccount -> handleDeactivateAccount(action) - DeactivateAccountAction.SsoAuthDone -> pendingAuthHandler.ssoAuthDone() + DeactivateAccountAction.SsoAuthDone -> { + _viewEvents.post(DeactivateAccountViewEvents.Loading()) + pendingAuthHandler.ssoAuthDone() + } is DeactivateAccountAction.PasswordAuthDone -> { _viewEvents.post(DeactivateAccountViewEvents.Loading()) pendingAuthHandler.passwordAuthDone(action.password) From c9eaf3005706693ed6093211160f89659627953a Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 22 Sep 2022 11:17:49 +0200 Subject: [PATCH 115/187] Updating the log in ssoAuthDone method to improve privacy --- .../java/im/vector/app/features/auth/PendingAuthHandler.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/auth/PendingAuthHandler.kt b/vector/src/main/java/im/vector/app/features/auth/PendingAuthHandler.kt index b986090e50..28a6f4b256 100644 --- a/vector/src/main/java/im/vector/app/features/auth/PendingAuthHandler.kt +++ b/vector/src/main/java/im/vector/app/features/auth/PendingAuthHandler.kt @@ -32,15 +32,15 @@ class PendingAuthHandler @Inject constructor( private val matrix: Matrix, private val activeSessionHolder: ActiveSessionHolder, ) { - var uiaContinuation: Continuation? = null var pendingAuth: UIABaseAuth? = null fun ssoAuthDone() { - Timber.d("ssoAuthDone $pendingAuth , continuation: $uiaContinuation") pendingAuth?.let { + Timber.d("ssoAuthDone, resuming action") uiaContinuation?.resume(it) } ?: run { + Timber.d("ssoAuthDone, cannot resume: no pendingAuth") uiaContinuation?.resumeWithException(IllegalArgumentException()) } } From 45b72483fe0de364d9456b8fd8cd41ac3d59fde3 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 10:22:33 +0200 Subject: [PATCH 116/187] Adding changelog entry --- changelog.d/7158.wip | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7158.wip diff --git a/changelog.d/7158.wip b/changelog.d/7158.wip new file mode 100644 index 0000000000..6c303281d8 --- /dev/null +++ b/changelog.d/7158.wip @@ -0,0 +1 @@ +[Device management] Rename a session From 1091ae41ad95c41bb5aa6f7331081c3b269c0a5d Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 11:18:49 +0200 Subject: [PATCH 117/187] Default structure for the new code --- vector/src/main/AndroidManifest.xml | 1 + .../v2/rename/RenameSessionActivity.kt | 52 +++++++++++++++ .../devices/v2/rename/RenameSessionArgs.kt | 25 ++++++++ .../v2/rename/RenameSessionFragment.kt | 63 +++++++++++++++++++ .../v2/rename/RenameSessionViewEvent.kt | 23 +++++++ .../v2/rename/RenameSessionViewModel.kt | 57 +++++++++++++++++ .../v2/rename/RenameSessionViewNavigator.kt | 28 +++++++++ .../v2/rename/RenameSessionViewState.kt | 28 +++++++++ .../res/layout/fragment_session_rename.xml | 8 +++ 9 files changed, 285 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionActivity.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionArgs.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewEvent.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewModel.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewNavigator.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewState.kt create mode 100644 vector/src/main/res/layout/fragment_session_rename.xml diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index bb8ca8cf5f..b16e4505a6 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -325,6 +325,7 @@ + diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionActivity.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionActivity.kt new file mode 100644 index 0000000000..36161610cd --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionActivity.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.rename + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import com.airbnb.mvrx.Mavericks +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.extensions.addFragment +import im.vector.app.core.platform.SimpleFragmentActivity + +/** + * Display the screen to rename a Session. + */ +@AndroidEntryPoint +class RenameSessionActivity : SimpleFragmentActivity() { + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + if (isFirstCreation()) { + addFragment( + container = views.container, + fragmentClass = RenameSessionFragment::class.java, + params = intent.getParcelableExtra(Mavericks.KEY_ARG) + ) + } + } + + companion object { + fun newIntent(context: Context, deviceId: String): Intent { + return Intent(context, RenameSessionActivity::class.java).apply { + putExtra(Mavericks.KEY_ARG, RenameSessionArgs(deviceId)) + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionArgs.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionArgs.kt new file mode 100644 index 0000000000..d43d472946 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionArgs.kt @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.rename + +import android.os.Parcelable +import kotlinx.parcelize.Parcelize + +@Parcelize +data class RenameSessionArgs( + val deviceId: String +) : Parcelable diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt new file mode 100644 index 0000000000..2b071e524d --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.rename + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import com.airbnb.mvrx.fragmentViewModel +import com.airbnb.mvrx.withState +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.databinding.FragmentSessionRenameBinding +import javax.inject.Inject + +/** + * Display the screen to rename a Session. + */ +@AndroidEntryPoint +class RenameSessionFragment : + VectorBaseFragment() { + + private val viewModel: RenameSessionViewModel by fragmentViewModel() + + @Inject lateinit var viewNavigator: RenameSessionViewNavigator + + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSessionRenameBinding { + return FragmentSessionRenameBinding.inflate(inflater, container, false) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + observeViewEvents() + } + + private fun observeViewEvents() { + viewModel.observeViewEvents { + when (it) { + is RenameSessionViewEvent.SessionRenamed -> { + viewNavigator.navigateBack(requireActivity()) + } + } + } + } + + override fun invalidate() = withState(viewModel) { _ -> + // TODO + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewEvent.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewEvent.kt new file mode 100644 index 0000000000..656c5bb165 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewEvent.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.rename + +import im.vector.app.core.platform.VectorViewEvents + +sealed class RenameSessionViewEvent : VectorViewEvents { + object SessionRenamed : RenameSessionViewEvent() +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewModel.kt new file mode 100644 index 0000000000..ebd30b7ef6 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewModel.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.rename + +import com.airbnb.mvrx.MavericksViewModelFactory +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import im.vector.app.core.di.MavericksAssistedViewModelFactory +import im.vector.app.core.di.hiltMavericksViewModelFactory +import im.vector.app.core.platform.EmptyAction +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.settings.devices.v2.overview.GetDeviceFullInfoUseCase +import kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach + +// TODO add unit tests +class RenameSessionViewModel @AssistedInject constructor( + @Assisted val initialState: RenameSessionViewState, + private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase, +) : VectorViewModel(initialState) { + + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + + @AssistedFactory + interface Factory : MavericksAssistedViewModelFactory { + override fun create(initialState: RenameSessionViewState): RenameSessionViewModel + } + + init { + observeSessionInfo(initialState.deviceId) + } + + private fun observeSessionInfo(deviceId: String) { + getDeviceFullInfoUseCase.execute(deviceId) + .onEach { setState { copy(deviceName = it.deviceInfo.displayName.orEmpty()) } } + .launchIn(viewModelScope) + } + + override fun handle(action: EmptyAction) { + // do nothing + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewNavigator.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewNavigator.kt new file mode 100644 index 0000000000..229d0bc70c --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewNavigator.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.rename + +import androidx.fragment.app.FragmentActivity +import javax.inject.Inject + +// TODO add unit tests +class RenameSessionViewNavigator @Inject constructor() { + + fun navigateBack(activity: FragmentActivity) { + activity.finish() + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewState.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewState.kt new file mode 100644 index 0000000000..18abba9c8d --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewState.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.rename + +import com.airbnb.mvrx.MavericksState + +data class RenameSessionViewState( + val deviceId: String, + val deviceName: String = "", +) : MavericksState { + constructor(args: RenameSessionArgs) : this( + deviceId = args.deviceId + ) +} diff --git a/vector/src/main/res/layout/fragment_session_rename.xml b/vector/src/main/res/layout/fragment_session_rename.xml new file mode 100644 index 0000000000..7911f36b00 --- /dev/null +++ b/vector/src/main/res/layout/fragment_session_rename.xml @@ -0,0 +1,8 @@ + + + + From 3de96a3a0cd72bc8d5e781dd94947187e3658570 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 14:03:10 +0200 Subject: [PATCH 118/187] Adding new method into navigator --- .../v2/overview/SessionOverviewFragment.kt | 2 +- .../overview/SessionOverviewViewNavigator.kt | 7 +++++- .../SessionOverviewViewNavigatorTest.kt | 25 ++++++++++++++++++- 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index 73991c5f20..af19de4ce0 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -118,7 +118,7 @@ class SessionOverviewFragment : private fun updateEntryDetails(deviceId: String) { views.sessionOverviewEntryDetails.setOnClickListener { - viewNavigator.navigateToSessionDetails(requireContext(), deviceId) + viewNavigator.goToSessionDetails(requireContext(), deviceId) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewNavigator.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewNavigator.kt index ef61856255..8c4d0345dc 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewNavigator.kt @@ -18,11 +18,16 @@ package im.vector.app.features.settings.devices.v2.overview import android.content.Context import im.vector.app.features.settings.devices.v2.details.SessionDetailsActivity +import im.vector.app.features.settings.devices.v2.rename.RenameSessionActivity import javax.inject.Inject class SessionOverviewViewNavigator @Inject constructor() { - fun navigateToSessionDetails(context: Context, deviceId: String) { + fun goToSessionDetails(context: Context, deviceId: String) { context.startActivity(SessionDetailsActivity.newIntent(context, deviceId)) } + + fun goToRenameSession(context: Context, deviceId: String) { + context.startActivity(RenameSessionActivity.newIntent(context, deviceId)) + } } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewNavigatorTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewNavigatorTest.kt index 56f1e5920d..3d38f3b3bf 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewNavigatorTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewNavigatorTest.kt @@ -18,6 +18,7 @@ package im.vector.app.features.settings.devices.v2.overview import android.content.Intent import im.vector.app.features.settings.devices.v2.details.SessionDetailsActivity +import im.vector.app.features.settings.devices.v2.rename.RenameSessionActivity import im.vector.app.test.fakes.FakeContext import io.mockk.every import io.mockk.mockk @@ -38,6 +39,7 @@ class SessionOverviewViewNavigatorTest { @Before fun setUp() { mockkObject(SessionDetailsActivity) + mockkObject(RenameSessionActivity) } @After @@ -52,7 +54,22 @@ class SessionOverviewViewNavigatorTest { context.givenStartActivity(intent) // When - sessionOverviewViewNavigator.navigateToSessionDetails(context.instance, A_SESSION_ID) + sessionOverviewViewNavigator.goToSessionDetails(context.instance, A_SESSION_ID) + + // Then + verify { + context.instance.startActivity(intent) + } + } + + @Test + fun `given a session id when navigating to rename screen then it starts the correct activity`() { + // Given + val intent = givenIntentForRenameSession(A_SESSION_ID) + context.givenStartActivity(intent) + + // When + sessionOverviewViewNavigator.goToRenameSession(context.instance, A_SESSION_ID) // Then verify { @@ -65,4 +82,10 @@ class SessionOverviewViewNavigatorTest { every { SessionDetailsActivity.newIntent(context.instance, sessionId) } returns intent return intent } + + private fun givenIntentForRenameSession(sessionId: String): Intent { + val intent = mockk() + every { RenameSessionActivity.newIntent(context.instance, sessionId) } returns intent + return intent + } } From 82fabf4a85efa23a7abea15de51bc9a1503ff28a Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 14:28:37 +0200 Subject: [PATCH 119/187] Adding menu with rename action in session overview screen --- .../src/main/res/values/strings.xml | 1 + .../app/core/di/MavericksViewModelModule.kt | 6 ++++++ .../v2/overview/SessionOverviewFragment.kt | 21 ++++++++++++++++++- .../v2/rename/RenameSessionFragment.kt | 9 ++++++++ .../main/res/menu/menu_session_overview.xml | 11 ++++++++++ 5 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 vector/src/main/res/menu/menu_session_overview.xml diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index d8f6222acf..8fd7d2e811 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3295,6 +3295,7 @@ Session ID Last activity IP address + Rename session %s\nis looking a little empty. diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt index 6fb2505386..62e7140742 100644 --- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt @@ -91,6 +91,7 @@ import im.vector.app.features.settings.devices.DevicesViewModel import im.vector.app.features.settings.devices.v2.details.SessionDetailsViewModel import im.vector.app.features.settings.devices.v2.othersessions.OtherSessionsViewModel import im.vector.app.features.settings.devices.v2.overview.SessionOverviewViewModel +import im.vector.app.features.settings.devices.v2.rename.RenameSessionViewModel import im.vector.app.features.settings.devtools.AccountDataViewModel import im.vector.app.features.settings.devtools.GossipingEventsPaperTrailViewModel import im.vector.app.features.settings.devtools.KeyRequestListViewModel @@ -653,4 +654,9 @@ interface MavericksViewModelModule { @IntoMap @MavericksViewModelKey(SessionDetailsViewModel::class) fun sessionDetailsViewModelFactory(factory: SessionDetailsViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + + @Binds + @IntoMap + @MavericksViewModelKey(RenameSessionViewModel::class) + fun renameSessionViewModelFactory(factory: RenameSessionViewModel.Factory): MavericksAssistedViewModelFactory<*, *> } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index af19de4ce0..0bf6e1d14f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -18,6 +18,7 @@ package im.vector.app.features.settings.devices.v2.overview import android.os.Bundle import android.view.LayoutInflater +import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.Toast @@ -31,6 +32,7 @@ import dagger.hilt.android.AndroidEntryPoint import im.vector.app.R import im.vector.app.core.date.VectorDateFormatter import im.vector.app.core.platform.VectorBaseFragment +import im.vector.app.core.platform.VectorMenuProvider import im.vector.app.core.resources.ColorProvider import im.vector.app.core.resources.DrawableProvider import im.vector.app.databinding.FragmentSessionOverviewBinding @@ -43,7 +45,8 @@ import javax.inject.Inject */ @AndroidEntryPoint class SessionOverviewFragment : - VectorBaseFragment() { + VectorBaseFragment(), + VectorMenuProvider { @Inject lateinit var viewNavigator: SessionOverviewViewNavigator @@ -103,6 +106,22 @@ class SessionOverviewFragment : views.sessionOverviewInfo.onLearnMoreClickListener = null } + override fun getMenuRes() = R.menu.menu_session_overview + + override fun handleMenuItemSelected(item: MenuItem): Boolean { + return when (item.itemId) { + R.id.sessionOverviewRename -> { + goToRenameSession() + true + } + else -> false + } + } + + private fun goToRenameSession() = withState(viewModel) { state -> + viewNavigator.goToRenameSession(requireContext(), state.deviceId) + } + override fun invalidate() = withState(viewModel) { state -> updateToolbar(state.isCurrentSession) updateEntryDetails(state.deviceId) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt index 2b071e524d..c8757f64c5 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt @@ -20,9 +20,11 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentSessionRenameBinding import javax.inject.Inject @@ -45,6 +47,13 @@ class RenameSessionFragment : override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) observeViewEvents() + initToolbar() + } + + private fun initToolbar() { + (activity as? AppCompatActivity) + ?.supportActionBar + ?.setTitle(R.string.device_manager_session_rename) } private fun observeViewEvents() { diff --git a/vector/src/main/res/menu/menu_session_overview.xml b/vector/src/main/res/menu/menu_session_overview.xml new file mode 100644 index 0000000000..7de3953dcc --- /dev/null +++ b/vector/src/main/res/menu/menu_session_overview.xml @@ -0,0 +1,11 @@ + + + + + From 54aec63f6ceb07102252be656075e5ad2ab1218a Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 14:31:54 +0200 Subject: [PATCH 120/187] Small improvement in code readability --- .../devices/v2/overview/SessionOverviewFragment.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt index 0bf6e1d14f..ccf68a18bc 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewFragment.kt @@ -23,7 +23,6 @@ import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.isGone import androidx.core.view.isVisible import com.airbnb.mvrx.Success import com.airbnb.mvrx.fragmentViewModel @@ -155,11 +154,7 @@ class SessionOverviewFragment : ) views.sessionOverviewInfo.render(infoViewState, dateFormatter, drawableProvider, colorProvider) } else { - hideSessionInfo() + views.sessionOverviewInfo.isVisible = false } } - - private fun hideSessionInfo() { - views.sessionOverviewInfo.isGone = true - } } From c3d359e58f363a67aae5bcd5d9b728b03bebb552 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 15:57:08 +0200 Subject: [PATCH 121/187] Adding edit text into the screen --- .../src/main/res/values/strings.xml | 3 ++ .../v2/rename/RenameSessionFragment.kt | 9 +++-- .../res/layout/fragment_session_rename.xml | 33 ++++++++++++++++++- 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index 8fd7d2e811..fdb04a6e76 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3296,6 +3296,9 @@ Last activity IP address Rename session + Session name + Custom session names can help you recognize your devices more easily. + Please be aware that session names are also visible to people you communicate with. %s\nis looking a little empty. diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt index c8757f64c5..7bb4eaaed7 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt @@ -40,6 +40,8 @@ class RenameSessionFragment : @Inject lateinit var viewNavigator: RenameSessionViewNavigator + private var renameEditTextInitialized = false + override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentSessionRenameBinding { return FragmentSessionRenameBinding.inflate(inflater, container, false) } @@ -66,7 +68,10 @@ class RenameSessionFragment : } } - override fun invalidate() = withState(viewModel) { _ -> - // TODO + override fun invalidate() = withState(viewModel) { state -> + if(renameEditTextInitialized.not()) { + views.renameSessionEditText.setText(state.deviceName) + renameEditTextInitialized = true + } } } diff --git a/vector/src/main/res/layout/fragment_session_rename.xml b/vector/src/main/res/layout/fragment_session_rename.xml index 7911f36b00..cd0a47ae82 100644 --- a/vector/src/main/res/layout/fragment_session_rename.xml +++ b/vector/src/main/res/layout/fragment_session_rename.xml @@ -1,8 +1,39 @@ + + + + + + + + From 7eab37e9d1a97215b11bef28efff50fe3f971d46 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 16:06:02 +0200 Subject: [PATCH 122/187] Small renaming of navigator method --- .../settings/devices/v2/rename/RenameSessionFragment.kt | 2 +- .../settings/devices/v2/rename/RenameSessionViewNavigator.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt index 7bb4eaaed7..49b2ee2cdf 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt @@ -62,7 +62,7 @@ class RenameSessionFragment : viewModel.observeViewEvents { when (it) { is RenameSessionViewEvent.SessionRenamed -> { - viewNavigator.navigateBack(requireActivity()) + viewNavigator.goBack(requireActivity()) } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewNavigator.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewNavigator.kt index 229d0bc70c..d26733635b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewNavigator.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewNavigator.kt @@ -22,7 +22,7 @@ import javax.inject.Inject // TODO add unit tests class RenameSessionViewNavigator @Inject constructor() { - fun navigateBack(activity: FragmentActivity) { + fun goBack(activity: FragmentActivity) { activity.finish() } } From 33cf3d3032947bc1d3b5f99a758e5c58abb617bf Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Mon, 19 Sep 2022 16:20:05 +0200 Subject: [PATCH 123/187] Setup a custom toolbar --- .../devices/v2/rename/RenameSessionActivity.kt | 9 ++++++--- .../devices/v2/rename/RenameSessionFragment.kt | 5 ++--- .../main/res/layout/fragment_session_rename.xml | 16 +++++++++++++++- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionActivity.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionActivity.kt index 36161610cd..11b3d5aebc 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionActivity.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionActivity.kt @@ -22,20 +22,23 @@ import android.os.Bundle import com.airbnb.mvrx.Mavericks import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment -import im.vector.app.core.platform.SimpleFragmentActivity +import im.vector.app.core.platform.VectorBaseActivity +import im.vector.app.databinding.ActivitySimpleBinding /** * Display the screen to rename a Session. */ @AndroidEntryPoint -class RenameSessionActivity : SimpleFragmentActivity() { +class RenameSessionActivity : VectorBaseActivity() { + + override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) if (isFirstCreation()) { addFragment( - container = views.container, + container = views.simpleFragmentContainer, fragmentClass = RenameSessionFragment::class.java, params = intent.getParcelableExtra(Mavericks.KEY_ARG) ) diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt index 49b2ee2cdf..ade23b5ee2 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt @@ -53,9 +53,8 @@ class RenameSessionFragment : } private fun initToolbar() { - (activity as? AppCompatActivity) - ?.supportActionBar - ?.setTitle(R.string.device_manager_session_rename) + setupToolbar(views.renameSessionToolbar) + .allowBack(useCross = true) } private fun observeViewEvents() { diff --git a/vector/src/main/res/layout/fragment_session_rename.xml b/vector/src/main/res/layout/fragment_session_rename.xml index cd0a47ae82..8ce1cbc453 100644 --- a/vector/src/main/res/layout/fragment_session_rename.xml +++ b/vector/src/main/res/layout/fragment_session_rename.xml @@ -4,6 +4,20 @@ android:layout_width="match_parent" android:layout_height="match_parent"> + + + + + + + app:layout_constraintTop_toBottomOf="@id/appBarLayout"> Date: Mon, 19 Sep 2022 17:27:06 +0200 Subject: [PATCH 124/187] Adding save button and view actions --- .../devices/v2/rename/RenameSessionAction.kt | 24 +++++++++++++++++++ .../v2/rename/RenameSessionFragment.kt | 20 +++++++++++++--- .../v2/rename/RenameSessionViewModel.kt | 19 +++++++++++---- .../res/layout/fragment_session_rename.xml | 11 ++++++++- 4 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionAction.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionAction.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionAction.kt new file mode 100644 index 0000000000..d175d1ea4a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionAction.kt @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2020 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.rename + +import im.vector.app.core.platform.VectorViewModelAction + +sealed class RenameSessionAction : VectorViewModelAction { + object SaveModifications : RenameSessionAction() + data class EditLocally(val editedName: String) : RenameSessionAction() +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt index ade23b5ee2..964fef1a99 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionFragment.kt @@ -20,11 +20,10 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import androidx.appcompat.app.AppCompatActivity +import androidx.core.widget.doOnTextChanged import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.withState import dagger.hilt.android.AndroidEntryPoint -import im.vector.app.R import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentSessionRenameBinding import javax.inject.Inject @@ -50,6 +49,8 @@ class RenameSessionFragment : super.onViewCreated(view, savedInstanceState) observeViewEvents() initToolbar() + initEditText() + initSaveButton() } private fun initToolbar() { @@ -57,6 +58,18 @@ class RenameSessionFragment : .allowBack(useCross = true) } + private fun initEditText() { + views.renameSessionEditText.doOnTextChanged { text, _, _, _ -> + viewModel.handle(RenameSessionAction.EditLocally(text.toString())) + } + } + + private fun initSaveButton() { + views.renameSessionSave.debouncedClicks { + viewModel.handle(RenameSessionAction.SaveModifications) + } + } + private fun observeViewEvents() { viewModel.observeViewEvents { when (it) { @@ -68,9 +81,10 @@ class RenameSessionFragment : } override fun invalidate() = withState(viewModel) { state -> - if(renameEditTextInitialized.not()) { + if (renameEditTextInitialized.not()) { views.renameSessionEditText.setText(state.deviceName) renameEditTextInitialized = true } + views.renameSessionSave.isEnabled = state.deviceName.isNotEmpty() } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewModel.kt index ebd30b7ef6..7e50ecce34 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionViewModel.kt @@ -22,7 +22,6 @@ import dagger.assisted.AssistedFactory import dagger.assisted.AssistedInject import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory -import im.vector.app.core.platform.EmptyAction import im.vector.app.core.platform.VectorViewModel import im.vector.app.features.settings.devices.v2.overview.GetDeviceFullInfoUseCase import kotlinx.coroutines.flow.launchIn @@ -32,7 +31,7 @@ import kotlinx.coroutines.flow.onEach class RenameSessionViewModel @AssistedInject constructor( @Assisted val initialState: RenameSessionViewState, private val getDeviceFullInfoUseCase: GetDeviceFullInfoUseCase, -) : VectorViewModel(initialState) { +) : VectorViewModel(initialState) { companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() @@ -51,7 +50,19 @@ class RenameSessionViewModel @AssistedInject constructor( .launchIn(viewModelScope) } - override fun handle(action: EmptyAction) { - // do nothing + override fun handle(action: RenameSessionAction) { + when (action) { + is RenameSessionAction.EditLocally -> handleEditLocally(action.editedName) + is RenameSessionAction.SaveModifications -> handleSaveModifications() + } + } + + private fun handleEditLocally(editedName: String) { + setState { copy(deviceName = editedName) } + } + + private fun handleSaveModifications() { + // TODO call use case to save the modifications + _viewEvents.post(RenameSessionViewEvent.SessionRenamed) } } diff --git a/vector/src/main/res/layout/fragment_session_rename.xml b/vector/src/main/res/layout/fragment_session_rename.xml index 8ce1cbc453..93b36566b1 100644 --- a/vector/src/main/res/layout/fragment_session_rename.xml +++ b/vector/src/main/res/layout/fragment_session_rename.xml @@ -14,8 +14,17 @@ android:id="@+id/renameSessionToolbar" android:layout_width="match_parent" android:layout_height="?actionBarSize" - app:title="@string/device_manager_session_rename"/> + app:title="@string/device_manager_session_rename"> +