| /* |
| * Copyright (C) 2019 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.tools.idea.wizard.template |
| import com.android.tools.idea.wizard.template.AssetNameConverter.Type |
| import com.google.common.base.CaseFormat |
| import com.google.common.io.Resources |
| import java.io.File |
| import java.net.URL |
| |
| data class GradleVersion(val major: Int, val minor: Int, val micro: Int) { |
| operator fun compareTo(other: GradleVersion) = when { |
| this == other -> 0 |
| this.major > other.major -> 1 |
| this.minor > other.minor -> 1 |
| this.micro > other.micro -> 1 |
| else -> -1 |
| } |
| } |
| |
| /** Converts an Activity class name into a suitable layout name. */ |
| fun activityToLayout(activityName: String, layoutName: String? = null): String = |
| if (activityName.isNotEmpty()) |
| AssetNameConverter(Type.ACTIVITY, activityName) |
| .overrideLayoutPrefix(layoutName) |
| .getValue(Type.LAYOUT) |
| else |
| "" |
| |
| /** Converts a Fragment class name into a suitable layout name. */ |
| fun fragmentToLayout(fragmentName: String, layoutName: String? = null): String = |
| if (fragmentName.isNotEmpty()) |
| AssetNameConverter(Type.FRAGMENT, fragmentName) |
| .overrideLayoutPrefix(layoutName ?: "fragment") |
| .getValue(Type.LAYOUT) |
| else |
| "" |
| |
| /** Similar to [camelCaseToUnderlines], but strips off common class suffixes such as "Activity", "Fragment", etc. */ |
| fun classToResource(name: String): String = |
| if (name.isNotEmpty()) |
| AssetNameConverter(Type.CLASS_NAME, name).getValue(Type.RESOURCE) |
| else "" |
| |
| /** |
| * Converts a String to Camel Case. The return will not contain any two consecutive upper case characters |
| * For example: |
| * MyCLASsName to MyClassName |
| * my_class_name to MyClassName |
| * URL to Url |
| **/ |
| fun toUpperCamelCase(string: String): String { |
| if (string.length <= 1) { |
| return string |
| } |
| |
| return buildString(string.length) { |
| var previous = ' ' |
| string.forEach { c -> |
| when { |
| c == '_' -> Unit |
| isEmpty() -> append(c.toUpperCase()) |
| last().isUpperCase() -> append(c.toLowerCase()) |
| previous == '_' -> append(c.toUpperCase()) |
| previous.isUpperCase() -> append(c.toLowerCase()) |
| else -> append(c) |
| } |
| previous = c |
| } |
| } |
| } |
| |
| fun camelCaseToUnderlines(string: String): String = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, string) |
| |
| fun underscoreToCamelCase( |
| string: String |
| ): String = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, string) |
| |
| fun underscoreToLowerCamelCase( |
| string: String |
| ): String = CaseFormat.LOWER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, string) |
| |
| fun escapeKotlinIdentifier(identifier: String): String = |
| identifier.split(".").joinToString(".") { if (it in kotlinKeywords) "`$it`" else it } |
| |
| /** |
| * Creates a Java class name out of the given string, if possible. |
| * For example, "My Project" becomes "MyProject", "hello" becomes "Hello", "Java's" becomes "Javas", and so on. |
| * |
| * @param string the string to be massaged into a Java class |
| * @return the string as a Java class, or null if a class name could not be extracted |
| */ |
| fun extractClassName(string: String): String? { |
| val javaIdentifier = string.dropWhile { !Character.isJavaIdentifierStart(it.toUpperCase()) }.filter(Character::isJavaIdentifierPart) |
| if (javaIdentifier.isBlank()) { |
| return null |
| } |
| return javaIdentifier.first().toUpperCase() + javaIdentifier.substring(1) |
| } |
| |
| fun layoutToActivity(name: String): String = AssetNameConverter(Type.LAYOUT, name).getValue(Type.ACTIVITY) |
| fun layoutToFragment(name: String): String = AssetNameConverter(Type.LAYOUT, name).getValue(Type.FRAGMENT) |
| |
| // TODO(qumeric): remove when we will drop support library in templates |
| fun getMaterialComponentName(mavenCoordinate: String, useAndroidX: Boolean): String { |
| if (!useAndroidX) { |
| return mavenCoordinate |
| } |
| val mapping = mapOf( |
| "android.arch.core.util.Function" to "androidx.arch.core.util.Function", |
| "android.arch.lifecycle.LiveData" to "androidx.lifecycle.LiveData", |
| "android.arch.lifecycle.MutableLiveData" to "androidx.lifecycle.MutableLiveData", |
| "android.arch.lifecycle.Observer" to "androidx.lifecycle.Observer", |
| "android.arch.lifecycle.Transformations" to "androidx.lifecycle.Transformations", |
| "android.arch.lifecycle.ViewModel" to "androidx.lifecycle.ViewModel", |
| "android.arch.lifecycle.ViewModelProvider" to "androidx.lifecycle.ViewModelProvider", |
| "android.support.annotation.NonNull" to "androidx.annotation.NonNull", |
| "android.support.annotation.Nullable" to "androidx.annotation.Nullable", |
| "android.support.annotation.StringRes" to "androidx.annotation.StringRes", |
| "android.support.constraint.ConstraintLayout" to "androidx.constraintlayout.widget.ConstraintLayout", |
| "android.support.constraint.Guideline" to "androidx.constraintlayout.widget.Guideline", |
| "android.support.design.widget.AppBarLayout" to "com.google.android.material.appbar.AppBarLayout", |
| "android.support.design.widget.BottomNavigationView" to "com.google.android.material.bottomnavigation.BottomNavigationView", |
| "android.support.design.widget.BottomSheetDialog" to "com.google.android.material.bottomsheet.BottomSheetDialog", |
| "android.support.design.widget.CollapsingToolbarLayout" to "com.google.android.material.appbar.CollapsingToolbarLayout", |
| "android.support.design.widget.CoordinatorLayout" to "androidx.coordinatorlayout.widget.CoordinatorLayout", |
| "android.support.design.widget.FloatingActionButton" to "com.google.android.material.floatingactionbutton.FloatingActionButton", |
| "android.support.design.widget.NavigationView" to "com.google.android.material.navigation.NavigationView", |
| "android.support.design.widget.Snackbar" to "com.google.android.material.snackbar.Snackbar", |
| "android.support.design.widget.TabLayout" to "com.google.android.material.tabs.TabLayout", |
| "android.support.design.widget.TabLayout" to "com.google.android.material.tabs.TabLayout", |
| "android.support.test.InstrumentationRegistry" to "androidx.test.platform.app.InstrumentationRegistry", |
| "android.support.test.runner.AndroidJUnit4" to "androidx.test.ext.junit.runners.AndroidJUnit4", |
| "android.support.test.runner.AndroidJUnitRunner" to "androidx.test.runner.AndroidJUnitRunner", |
| "android.support.v17.leanback.app.BackgroundManager" to "androidx.leanback.app.BackgroundManager", |
| "android.support.v17.leanback.app.BrowseSupportFragment" to "androidx.leanback.app.BrowseSupportFragment", |
| "android.support.v17.leanback.app.DetailsSupportFragment" to "androidx.leanback.app.DetailsSupportFragment", |
| "android.support.v17.leanback.app.DetailsSupportFragmentBackgroundController" to "androidx.leanback.app.DetailsSupportFragmentBackgroundController", |
| "android.support.v17.leanback.app.ErrorSupportFragment" to "androidx.leanback.app.ErrorSupportFragment", |
| "android.support.v17.leanback.app.VideoSupportFragment" to "androidx.leanback.app.VideoSupportFragment", |
| "android.support.v17.leanback.app.VideoSupportFragmentGlueHost" to "androidx.leanback.app.VideoSupportFragmentGlueHost", |
| "android.support.v17.leanback.media.MediaPlayerAdapter" to "androidx.leanback.media.MediaPlayerAdapter", |
| "android.support.v17.leanback.media.PlaybackTransportControlGlue" to "androidx.leanback.media.PlaybackTransportControlGlue", |
| "android.support.v17.leanback.widget.AbstractDetailsDescriptionPresenter" to "androidx.leanback.widget.AbstractDetailsDescriptionPresenter", |
| "android.support.v17.leanback.widget.Action" to "androidx.leanback.widget.Action", |
| "android.support.v17.leanback.widget.ArrayObjectAdapter" to "androidx.leanback.widget.ArrayObjectAdapter", |
| "android.support.v17.leanback.widget.ClassPresenterSelector" to "androidx.leanback.widget.ClassPresenterSelector", |
| "android.support.v17.leanback.widget.DetailsOverviewRow" to "androidx.leanback.widget.DetailsOverviewRow", |
| "android.support.v17.leanback.widget.FullWidthDetailsOverviewRowPresenter" to "androidx.leanback.widget.FullWidthDetailsOverviewRowPresenter", |
| "android.support.v17.leanback.widget.FullWidthDetailsOverviewSharedElementHelper" to "androidx.leanback.widget.FullWidthDetailsOverviewSharedElementHelper", |
| "android.support.v17.leanback.widget.HeaderItem" to "androidx.leanback.widget.HeaderItem", |
| "android.support.v17.leanback.widget.ImageCardView" to "androidx.leanback.widget.ImageCardView", |
| "android.support.v17.leanback.widget.ListRow" to "androidx.leanback.widget.ListRow", |
| "android.support.v17.leanback.widget.ListRowPresenter" to "androidx.leanback.widget.ListRowPresenter", |
| "android.support.v17.leanback.widget.OnActionClickedListener" to "androidx.leanback.widget.OnActionClickedListener", |
| "android.support.v17.leanback.widget.OnItemViewClickedListener" to "androidx.leanback.widget.OnItemViewClickedListener", |
| "android.support.v17.leanback.widget.OnItemViewSelectedListener" to "androidx.leanback.widget.OnItemViewSelectedListener", |
| "android.support.v17.leanback.widget.PlaybackControlsRow" to "androidx.leanback.widget.PlaybackControlsRow", |
| "android.support.v17.leanback.widget.Presenter" to "androidx.leanback.widget.Presenter", |
| "android.support.v17.leanback.widget.Row" to "androidx.leanback.widget.Row", |
| "android.support.v17.leanback.widget.RowPresenter" to "androidx.leanback.widget.RowPresenter", |
| "android.support.v4.app.ActivityOptionsCompat" to "androidx.core.app.ActivityOptionsCompat", |
| "android.support.v4.app.Fragment" to "androidx.fragment.app.Fragment", |
| "android.support.v4.app.FragmentActivity" to "androidx.fragment.app.FragmentActivity", |
| "android.support.v4.app.FragmentManager" to "androidx.fragment.app.FragmentManager", |
| "android.support.v4.app.FragmentPagerAdapter" to "androidx.fragment.app.FragmentPagerAdapter", |
| "android.support.v4.app.NotificationCompat" to "androidx.core.app.NotificationCompat", |
| "android.support.v4.app.NotificationCompat.CarExtender" to "androidx.core.app.NotificationCompat.CarExtender", |
| "android.support.v4.app.NotificationCompat.CarExtender.UnreadConversation" to "androidx.core.app.NotificationCompat.CarExtender.UnreadConversation", |
| "android.support.v4.app.NotificationManagerCompat" to "androidx.core.app.NotificationManagerCompat", |
| "android.support.v4.app.RemoteInput" to "androidx.core.app.RemoteInput", |
| "android.support.v4.content.ContextCompat" to "androidx.core.content.ContextCompat", |
| "android.support.v4.media.MediaBrowserServiceCompat" to "androidx.media.MediaBrowserServiceCompat", |
| "android.support.v4.view.ViewPager" to "androidx.viewpager.widget.ViewPager", |
| "android.support.v4.widget.DrawerLayout" to "androidx.drawerlayout.widget.DrawerLayout", |
| "android.support.v4.widget.NestedScrollView" to "androidx.core.widget.NestedScrollView", |
| "android.support.v7.app.ActionBar" to "androidx.appcompat.app.ActionBar", |
| "android.support.v7.app.AppCompatActivity" to "androidx.appcompat.app.AppCompatActivity", |
| "android.support.v7.graphics.Palette" to "androidx.palette.graphics.Palette", |
| "android.support.v7.widget.GridLayoutManager" to "androidx.recyclerview.widget.GridLayoutManager", |
| "android.support.v7.widget.LinearLayoutManager" to "androidx.recyclerview.widget.LinearLayoutManager", |
| "android.support.v7.widget.RecyclerView" to "androidx.recyclerview.widget.RecyclerView", |
| "android.support.v7.widget.Toolbar" to "androidx.appcompat.widget.Toolbar", |
| "android.support.wear.widget.BoxInsetLayout" to "androidx.wear.widget.BoxInsetLayout", |
| "android.support.wear.widget.SwipeDismissFrameLayout" to "androidx.wear.widget.SwipeDismissFrameLayout" |
| ) |
| |
| val androidXCoordinate = mapping[mavenCoordinate] |
| |
| require(androidXCoordinate != null) { |
| """ |
| Unknown dependency. |
| It is recommended to avoid this method in favor of using androidX dependencies directly and setting androidX TemplateConstraint to true |
| """ |
| } |
| |
| return androidXCoordinate |
| } |
| |
| // From https://github.com/JetBrains/kotlin/blob/master/core/descriptors/src/org/jetbrains/kotlin/renderer/KeywordStringsGenerated.java |
| private val kotlinKeywords = listOf( |
| "package", "as", "typealias", "class", "this", "super", "val", "var", "fun", "for", "null", "true", "false", "is", "in", |
| "throw", "return", "break", "continue", "object", "if", "try", "else", "while", "do", "when", "interface", "typeof") |
| |
| fun extractLetters(string: String) = string.filter(Character::isLetter) |
| |
| /** |
| * Finds a resource given a file path and a context class. The implementation takes cares of the details of different file path |
| * separators in different operating systems. |
| */ |
| fun findResource(contextClass: Class<Any>, from: File) : URL { |
| // Windows file paths use '\', but resources are always '/', and they need to start at root. |
| return Resources.getResource(contextClass, "/${from.path.replace('\\', '/')}") |
| } |
| |
| /** |
| * Creates a domain name from the form of package name (e.g. from "com.example.www" to "www.example.com"). |
| * Returns an example domain if the [packageName] is empty. |
| */ |
| fun packageNameToDomain(packageName: String): String { |
| val domain = packageName |
| .split(".") |
| .map { it.trim() } |
| .filter { it.isNotEmpty() } |
| .reversed() |
| .joinToString(".") |
| return if (domain.isEmpty()) "example.com" else domain |
| } |