[go: nahoru, domu]

blob: b5ff4b21a9bb4d6c1f0b709db9872b02f84cbf39 [file] [log] [blame]
/*
* Copyright 2021 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 androidx.window.embedding
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.view.WindowMetrics
import androidx.window.core.ExperimentalWindowApi
import androidx.window.core.PredicateAdapter
import androidx.window.extensions.embedding.ActivityRule as OEMActivityRule
import androidx.window.extensions.embedding.ActivityRule.Builder as ActivityRuleBuilder
import androidx.window.extensions.embedding.EmbeddingRule as OEMEmbeddingRule
import androidx.window.extensions.embedding.SplitInfo as OEMSplitInfo
import androidx.window.extensions.embedding.SplitPairRule as OEMSplitPairRule
import androidx.window.extensions.embedding.SplitPairRule.Builder as SplitPairRuleBuilder
import androidx.window.extensions.embedding.SplitPlaceholderRule as OEMSplitPlaceholderRule
import androidx.window.extensions.embedding.SplitPlaceholderRule.Builder as SplitPlaceholderRuleBuilder
/**
* Adapter class that translates data classes between Extension and Jetpack interfaces.
*/
@ExperimentalWindowApi
internal class EmbeddingAdapter(
private val predicateAdapter: PredicateAdapter
) {
fun translate(splitInfoList: List<OEMSplitInfo>): List<SplitInfo> {
return splitInfoList.map(::translate)
}
private fun translate(splitInfo: OEMSplitInfo): SplitInfo {
val primaryActivityStack = splitInfo.primaryActivityStack
val isPrimaryStackEmpty = try {
primaryActivityStack.isEmpty
} catch (e: NoSuchMethodError) {
// Users may use older library which #isEmpty hasn't existed. Provide a fallback value
// for this case to avoid crash.
false
}
val primaryFragment = ActivityStack(primaryActivityStack.activities, isPrimaryStackEmpty)
val secondaryActivityStack = splitInfo.secondaryActivityStack
val isSecondaryStackEmpty = try {
secondaryActivityStack.isEmpty
} catch (e: NoSuchMethodError) {
// Users may use older library which #isEmpty hasn't existed. Provide a fallback value
// for this case to avoid crash.
false
}
val secondaryFragment = ActivityStack(
secondaryActivityStack.activities,
isSecondaryStackEmpty
)
return SplitInfo(primaryFragment, secondaryFragment, splitInfo.splitRatio)
}
@SuppressLint("ClassVerificationFailure", "NewApi")
private fun translateActivityPairPredicates(splitPairFilters: Set<SplitPairFilter>): Any {
return predicateAdapter.buildPairPredicate(
Activity::class,
Activity::class
) { first: Activity, second: Activity ->
splitPairFilters.any { filter -> filter.matchesActivityPair(first, second) }
}
}
@SuppressLint("ClassVerificationFailure", "NewApi")
private fun translateActivityIntentPredicates(splitPairFilters: Set<SplitPairFilter>): Any {
return predicateAdapter.buildPairPredicate(
Activity::class,
Intent::class
) { first, second ->
splitPairFilters.any { filter -> filter.matchesActivityIntentPair(first, second) }
}
}
@SuppressLint("ClassVerificationFailure", "NewApi")
private fun translateParentMetricsPredicate(splitRule: SplitRule): Any {
return predicateAdapter.buildPredicate(WindowMetrics::class) { windowMetrics ->
splitRule.checkParentMetrics(windowMetrics)
}
}
@SuppressLint("ClassVerificationFailure", "NewApi")
private fun translateActivityPredicates(activityFilters: Set<ActivityFilter>): Any {
return predicateAdapter.buildPredicate(Activity::class) { activity ->
activityFilters.any { filter -> filter.matchesActivity(activity) }
}
}
@SuppressLint("ClassVerificationFailure", "NewApi")
private fun translateIntentPredicates(activityFilters: Set<ActivityFilter>): Any {
return predicateAdapter.buildPredicate(Intent::class) { intent ->
activityFilters.any { filter -> filter.matchesIntent(intent) }
}
}
@SuppressLint("WrongConstant") // Converting from Jetpack to Extensions constants
private fun translateSplitPairRule(
rule: SplitPairRule,
predicateClass: Class<*>
): OEMSplitPairRule {
val builder = SplitPairRuleBuilder::class.java.getConstructor(
predicateClass,
predicateClass,
predicateClass
).newInstance(
translateActivityPairPredicates(rule.filters),
translateActivityIntentPredicates(rule.filters),
translateParentMetricsPredicate(rule)
)
.setSplitRatio(rule.splitRatio)
.setLayoutDirection(rule.layoutDirection)
.setShouldClearTop(rule.clearTop)
try {
builder.setFinishPrimaryWithSecondary(rule.finishPrimaryWithSecondary)
builder.setFinishSecondaryWithPrimary(rule.finishSecondaryWithPrimary)
} catch (error: NoSuchMethodError) {
// TODO(b/205181250): Old extension interface, to be dropped with next developer preview
}
return builder.build()
}
@SuppressLint("WrongConstant") // Converting from Jetpack to Extensions constants
private fun translateSplitPlaceholderRule(
rule: SplitPlaceholderRule,
predicateClass: Class<*>
): OEMSplitPlaceholderRule {
val builder = SplitPlaceholderRuleBuilder::class.java.getConstructor(
Intent::class.java,
predicateClass,
predicateClass,
predicateClass
).newInstance(
rule.placeholderIntent,
translateActivityPredicates(rule.filters),
translateIntentPredicates(rule.filters),
translateParentMetricsPredicate(rule)
)
.setSplitRatio(rule.splitRatio)
.setLayoutDirection(rule.layoutDirection)
try {
builder.setSticky(rule.isSticky)
builder.setFinishPrimaryWithSecondary(rule.finishPrimaryWithSecondary)
} catch (error: NoSuchMethodError) {
// TODO(b/205181250): Old extension interface, to be dropped with next developer preview
}
return builder.build()
}
private fun translateActivityRule(
rule: ActivityRule,
predicateClass: Class<*>
): OEMActivityRule {
return ActivityRuleBuilder::class.java.getConstructor(
predicateClass,
predicateClass
).newInstance(
translateActivityPredicates(rule.filters),
translateIntentPredicates(rule.filters)
)
.setShouldAlwaysExpand(rule.alwaysExpand)
.build()
}
fun translate(rules: Set<EmbeddingRule>): Set<OEMEmbeddingRule> {
val predicateClass = predicateAdapter.predicateClassOrNull() ?: return emptySet()
return rules.map { rule ->
when (rule) {
is SplitPairRule -> translateSplitPairRule(rule, predicateClass)
is SplitPlaceholderRule -> translateSplitPlaceholderRule(rule, predicateClass)
is ActivityRule -> translateActivityRule(rule, predicateClass)
else -> throw IllegalArgumentException("Unsupported rule type")
}
}.toSet()
}
}