SplitPairFilter.kt
/*
* 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.app.Activity
import android.content.ComponentName
import android.content.Intent
import android.util.Log
import androidx.window.core.ExperimentalWindowApi
import androidx.window.embedding.MatcherUtils.areComponentsMatching
import androidx.window.embedding.MatcherUtils.sDebugMatchers
import androidx.window.embedding.MatcherUtils.sMatchersTag
/**
* Filter used to find if a pair of activities should be put in a split. Applied to the base /
* primary activity and an intent starting a secondary activity.
*/
@ExperimentalWindowApi
class SplitPairFilter(
/**
* Component name of the primary activity in the split. Must be non-empty. Can contain a single
* wildcard at the end.
* Supported formats: "package/class", "package/*", "package/suffix.*",
* "*/*"
*/
val primaryActivityName: ComponentName,
/**
* Component name in the intent for the secondary activity in the split. Must be non-empty.
* Can contain a single wildcard at the end.
* Supported formats:
* <li>package/class</li>
* <li>package/\*</li>
* <li>package/suffix.\*</li>
* <li>\*\/\*</li>
*/
val secondaryActivityName: ComponentName,
/**
* Action used for secondary activity launch.
*/
val secondaryActivityIntentAction: String?
) {
fun matchesActivityPair(primaryActivity: Activity, secondaryActivity: Activity): Boolean {
// Check if the activity component names match
var match = areComponentsMatching(primaryActivity.componentName, primaryActivityName) &&
areComponentsMatching(secondaryActivity.componentName, secondaryActivityName)
// If the intent is not empty - check that the rest of the filter fields match
if (secondaryActivity.intent != null) {
match = match && matchesActivityIntentPair(primaryActivity, secondaryActivity.intent)
}
if (sDebugMatchers) {
val matchString = if (match) "MATCH" else "NO MATCH"
Log.d(
sMatchersTag,
"Checking filter $this against activity pair: (${primaryActivity.componentName}, " +
"${secondaryActivity.componentName}) - $matchString"
)
}
return match
}
fun matchesActivityIntentPair(
primaryActivity: Activity,
secondaryActivityIntent: Intent
): Boolean {
val inPrimaryActivityName = primaryActivity.componentName
val match = if (
!areComponentsMatching(inPrimaryActivityName, primaryActivityName)
) {
false
} else if (
!areComponentsMatching(secondaryActivityIntent.component, secondaryActivityName)
) {
false
} else {
secondaryActivityIntentAction == null ||
secondaryActivityIntentAction == secondaryActivityIntent.action
}
if (sDebugMatchers) {
val matchString = if (match) "MATCH" else "NO MATCH"
Log.w(
sMatchersTag,
"Checking filter $this against activity-intent pair: " +
"(${primaryActivity.componentName}, $secondaryActivityIntent) - $matchString"
)
}
return match
}
init {
val primaryPackageName = primaryActivityName.packageName
val primaryClassName = primaryActivityName.className
val secondaryPackageName = secondaryActivityName.packageName
val secondaryClassName = secondaryActivityName.className
require(
!(primaryPackageName.isEmpty() || secondaryPackageName.isEmpty())
) { "Package name must not be empty" }
require(
!(primaryClassName.isEmpty() || secondaryClassName.isEmpty())
) { "Activity class name must not be empty." }
require(
!(
primaryPackageName.contains("*") &&
primaryPackageName.indexOf("*") != primaryPackageName.length - 1
)
) { "Wildcard in package name is only allowed at the end." }
require(
!(
primaryClassName.contains("*") &&
primaryClassName.indexOf("*") != primaryClassName.length - 1
)
) { "Wildcard in class name is only allowed at the end." }
require(
!(
secondaryPackageName.contains("*") &&
secondaryPackageName.indexOf("*") != secondaryPackageName.length - 1
)
) { "Wildcard in package name is only allowed at the end." }
require(
!(
secondaryClassName.contains("*") &&
secondaryClassName.indexOf("*") != secondaryClassName.length - 1
)
) { "Wildcard in class name is only allowed at the end." }
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is SplitPairFilter) return false
if (primaryActivityName != other.primaryActivityName) return false
if (secondaryActivityName != other.secondaryActivityName) return false
if (secondaryActivityIntentAction != other.secondaryActivityIntentAction) return false
return true
}
override fun hashCode(): Int {
var result = primaryActivityName.hashCode()
result = 31 * result + secondaryActivityName.hashCode()
result = 31 * result + (secondaryActivityIntentAction?.hashCode() ?: 0)
return result
}
override fun toString(): String {
return "SplitPairFilter{primaryActivityName=$primaryActivityName, " +
"secondaryActivityName=$secondaryActivityName, " +
"secondaryActivityAction=$secondaryActivityIntentAction}"
}
}