mirror of
https://github.com/Tencent/QMUI_Android.git
synced 2026-10-17 04:31:16 +08:00
new feature: scheme
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface ActivityScheme {
|
||||
String name();
|
||||
String[] required() default {};
|
||||
Class<?> customFactory() default void.class;
|
||||
String[] keysWithIntValue() default {};
|
||||
String[] keysWithBoolValue() default {};
|
||||
String[] keysWithLongValue() default {};
|
||||
String[] keysWithFloatValue() default {};
|
||||
String[] keysWithDoubleValue() default {};
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.annotation;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.CLASS)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface FragmentScheme {
|
||||
String name();
|
||||
Class<?>[] activities();
|
||||
String[] required() default {};
|
||||
boolean forceNewActivity() default false;
|
||||
String forceNewActivityKey() default "";
|
||||
Class<?> customFactory() default void.class;
|
||||
String[] keysWithIntValue() default {};
|
||||
String[] keysWithBoolValue() default {};
|
||||
String[] keysWithLongValue() default {};
|
||||
String[] keysWithFloatValue() default {};
|
||||
String[] keysWithDoubleValue() default {};
|
||||
}
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch;
|
||||
|
||||
import com.squareup.javapoet.ClassName;
|
||||
@@ -5,12 +20,15 @@ import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.WildcardTypeName;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.Filer;
|
||||
import javax.annotation.processing.Messager;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ElementKind;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
@@ -25,14 +43,22 @@ import static javax.lang.model.element.ElementKind.INTERFACE;
|
||||
|
||||
public abstract class BaseProcessor extends AbstractProcessor {
|
||||
|
||||
static final String ACTIVITY_TYPE = "android.app.Activity";
|
||||
static final String FRAGMENT_ACTIVITY_TYPE = "androidx.fragment.app.FragmentActivity";
|
||||
static final String FRAGMENT_TYPE = "androidx.fragment.app.Fragment";
|
||||
static final String QMUI_FRAGMENT_ACTIVITY_TYPE = "com.qmuiteam.qmui.arch.QMUIFragmentActivity";
|
||||
static final String QMUI_FRAGMENT_TYPE = "com.qmuiteam.qmui.arch.QMUIFragment";
|
||||
static final String QMUI_ACTIVITY_TYPE = "com.qmuiteam.qmui.arch.QMUIActivity";
|
||||
|
||||
|
||||
static final ClassName QMUIFragmentActivityName = ClassName.get(
|
||||
"com.qmuiteam.qmui.arch", "QMUIFragmentActivity");
|
||||
static final ClassName QMUIFragmentName = ClassName.get(
|
||||
"com.qmuiteam.qmui.arch", "QMUIFragment");
|
||||
static ClassName MapName = ClassName.get("java.util", "Map");
|
||||
static ClassName ListName = ClassName.get("java.util", "List");
|
||||
static ClassName ArrayMapName = ClassName.get("android.util", "ArrayMap");
|
||||
static ClassName ArrayListName = ClassName.get("java.util", "ArrayList");
|
||||
static ClassName HashMapName = ClassName.get("java.util", "HashMap");
|
||||
static ClassName IntegerName = ClassName.get("java.lang", "Integer");
|
||||
static ClassName StringName = ClassName.get("java.lang", "String");
|
||||
@@ -140,4 +166,27 @@ public abstract class BaseProcessor extends AbstractProcessor {
|
||||
return typeMirror instanceof DeclaredType
|
||||
&& ((DeclaredType) typeMirror).asElement().getKind() == INTERFACE;
|
||||
}
|
||||
|
||||
static AnnotationMirror getAnnotationMirror(Element element, Class<?> annotation) {
|
||||
List<? extends AnnotationMirror> list = element.getAnnotationMirrors();
|
||||
if (list == null || list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
for (AnnotationMirror item : list) {
|
||||
if (item.getAnnotationType().toString().equals(annotation.getName())) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static AnnotationValue getAnnotationValue(AnnotationMirror annotationMirror, String key) {
|
||||
Map<? extends ExecutableElement, ? extends AnnotationValue> map = annotationMirror.getElementValues();
|
||||
for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> item : map.entrySet()) {
|
||||
if (item.getKey().getSimpleName().toString().equals(key)) {
|
||||
return item.getValue();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
|
||||
@@ -0,0 +1,388 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch;
|
||||
|
||||
import com.google.auto.service.AutoService;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.qmuiteam.qmui.arch.annotation.ActivityScheme;
|
||||
import com.qmuiteam.qmui.arch.annotation.FragmentScheme;
|
||||
import com.squareup.javapoet.ClassName;
|
||||
import com.squareup.javapoet.CodeBlock;
|
||||
import com.squareup.javapoet.FieldSpec;
|
||||
import com.squareup.javapoet.JavaFile;
|
||||
import com.squareup.javapoet.MethodSpec;
|
||||
import com.squareup.javapoet.ParameterizedTypeName;
|
||||
import com.squareup.javapoet.TypeName;
|
||||
import com.squareup.javapoet.TypeSpec;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.annotation.processing.Processor;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.lang.model.element.AnnotationMirror;
|
||||
import javax.lang.model.element.AnnotationValue;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.Modifier;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.element.VariableElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.MirroredTypesException;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
|
||||
@AutoService(Processor.class)
|
||||
public class SchemeProcessor extends BaseProcessor {
|
||||
private static String QMUISchemeIntentFactoryType = "com.qmuiteam.qmui.arch.scheme.QMUISchemeIntentFactory";
|
||||
private static String QMUISchemeFragmentFactoryType = "com.qmuiteam.qmui.arch.scheme.QMUISchemeFragmentFactory";
|
||||
|
||||
private static ClassName SchemeMap = ClassName.get(
|
||||
"com.qmuiteam.qmui.arch.scheme", "SchemeMap");
|
||||
private static ClassName SchemeItem = ClassName.get(
|
||||
"com.qmuiteam.qmui.arch.scheme", "SchemeItem");
|
||||
private static ClassName ActivitySchemeItem = ClassName.get(
|
||||
"com.qmuiteam.qmui.arch.scheme", "ActivitySchemeItem");
|
||||
private static ClassName FragmentSchemeItem = ClassName.get(
|
||||
"com.qmuiteam.qmui.arch.scheme", "FragmentSchemeItem");
|
||||
|
||||
private static TypeName SchemeItemList = ParameterizedTypeName.get(ListName, SchemeItem);
|
||||
private static TypeName MapByAction = ParameterizedTypeName.get(MapName,
|
||||
StringName, SchemeItemList);
|
||||
private static TypeName MapForSchemeRequired = ParameterizedTypeName.get(ArrayMapName,
|
||||
StringName, StringName);
|
||||
|
||||
@Override
|
||||
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
||||
Set<? extends Element> activitySchemes = roundEnv.getElementsAnnotatedWith(ActivityScheme.class);
|
||||
Set<? extends Element> fragmentSchemes = roundEnv.getElementsAnnotatedWith(FragmentScheme.class);
|
||||
if (activitySchemes.isEmpty() && fragmentSchemes.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
TypeSpec.Builder classBuilder = TypeSpec
|
||||
.classBuilder(SchemeMap.simpleName() + "Impl")
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addSuperinterface(SchemeMap);
|
||||
classBuilder.addField(FieldSpec.builder(MapByAction, "mSchemeMap")
|
||||
.addModifiers(Modifier.PRIVATE)
|
||||
.build());
|
||||
|
||||
|
||||
MethodSpec.Builder constructorBuilder = MethodSpec.constructorBuilder()
|
||||
.addModifiers(Modifier.PUBLIC)
|
||||
.addStatement("mSchemeMap = new $T<>()", HashMapName);
|
||||
|
||||
|
||||
Map<String, List<Item>> schemeMap = new HashMap<>();
|
||||
for (Element element : activitySchemes) {
|
||||
if (element instanceof TypeElement) {
|
||||
TypeElement classElement = (TypeElement) element;
|
||||
TypeMirror elementType = classElement.asType();
|
||||
boolean isActivity = isSubtypeOfType(elementType, ACTIVITY_TYPE);
|
||||
if (!isActivity) {
|
||||
error(element, "Must annotated on subclasses of Activity");
|
||||
} else {
|
||||
ActivityScheme annotation = element.getAnnotation(ActivityScheme.class);
|
||||
String name = annotation.name();
|
||||
List<Item> elements = schemeMap.get(name);
|
||||
if (elements == null) {
|
||||
elements = new ArrayList<>();
|
||||
schemeMap.put(name, elements);
|
||||
}
|
||||
elements.add(new Item(true, classElement, elementType, annotation.required()));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Element element : fragmentSchemes) {
|
||||
if (element instanceof TypeElement) {
|
||||
TypeElement classElement = (TypeElement) element;
|
||||
TypeMirror elementType = classElement.asType();
|
||||
boolean isQMUIFragment = isSubtypeOfType(elementType, QMUI_FRAGMENT_TYPE);
|
||||
if (!isQMUIFragment) {
|
||||
error(element, "Must annotated on subclasses of QMUIFragment");
|
||||
} else {
|
||||
FragmentScheme annotation = element.getAnnotation(FragmentScheme.class);
|
||||
String name = annotation.name();
|
||||
List<Item> elements = schemeMap.get(name);
|
||||
if (elements == null) {
|
||||
elements = new ArrayList<>();
|
||||
schemeMap.put(name, elements);
|
||||
}
|
||||
elements.add(new Item(false, classElement, elementType, annotation.required()));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructorBuilder.addStatement("$T elements", SchemeItemList);
|
||||
constructorBuilder.addStatement("$T required = null", MapForSchemeRequired);
|
||||
for (String key : schemeMap.keySet()) {
|
||||
List<Item> items = schemeMap.get(key);
|
||||
constructorBuilder.addStatement("elements = new $T<>()", ArrayListName);
|
||||
items.sort(new Comparator<Item>() {
|
||||
@Override
|
||||
public int compare(Item item, Item t1) {
|
||||
int c1 = item.getRequiredCount();
|
||||
int c2 = t1.getRequiredCount();
|
||||
return Integer.compare(c2, c1);
|
||||
}
|
||||
});
|
||||
for (Item item : items) {
|
||||
ClassName elementName = ClassName.get(item.element);
|
||||
if (item.isActivity) {
|
||||
ActivityScheme annotation = item.element.getAnnotation(ActivityScheme.class);
|
||||
AnnotationMirror annotationMirror = getAnnotationMirror(item.element, ActivityScheme.class);
|
||||
if (annotationMirror == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
appendRequired(constructorBuilder, annotation.required());
|
||||
|
||||
CodeBlock customFactory = generateCustomFactory(true, annotationMirror);
|
||||
CodeBlock intParam = generateTypedParams(annotation.keysWithIntValue());
|
||||
CodeBlock boolParam = generateTypedParams(annotation.keysWithBoolValue());
|
||||
CodeBlock longParam = generateTypedParams(annotation.keysWithLongValue());
|
||||
CodeBlock floatParam = generateTypedParams(annotation.keysWithFloatValue());
|
||||
CodeBlock doubleParam = generateTypedParams(annotation.keysWithDoubleValue());
|
||||
|
||||
CodeBlock codeBlock = CodeBlock.builder()
|
||||
.add("elements.add(")
|
||||
/**/.add("new $T(", ActivitySchemeItem)
|
||||
/*---*/.add("$T.class", elementName)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(customFactory)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add("required")
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(intParam)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(boolParam)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(longParam)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(floatParam)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(doubleParam)
|
||||
/**/.add(")")
|
||||
.add(")")
|
||||
.build();
|
||||
constructorBuilder.addStatement(codeBlock);
|
||||
} else {
|
||||
FragmentScheme annotation = item.element.getAnnotation(FragmentScheme.class);
|
||||
AnnotationMirror annotationMirror = getAnnotationMirror(item.element, FragmentScheme.class);
|
||||
if (annotationMirror == null) {
|
||||
continue;
|
||||
}
|
||||
appendRequired(constructorBuilder, annotation.required());
|
||||
CodeBlock customFactory = generateCustomFactory(false, annotationMirror);
|
||||
CodeBlock activities = generateFragmentHostActivityList(annotation);
|
||||
CodeBlock intParam = generateTypedParams(annotation.keysWithIntValue());
|
||||
CodeBlock boolParam = generateTypedParams(annotation.keysWithBoolValue());
|
||||
CodeBlock longParam = generateTypedParams(annotation.keysWithLongValue());
|
||||
CodeBlock floatParam = generateTypedParams(annotation.keysWithFloatValue());
|
||||
CodeBlock doubleParam = generateTypedParams(annotation.keysWithDoubleValue());
|
||||
|
||||
CodeBlock codeBlock = CodeBlock.builder()
|
||||
.add("elements.add(")
|
||||
/**/.add("new $T(", FragmentSchemeItem)
|
||||
/*---*/.add("$T.class", elementName)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(activities)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(customFactory)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add("$L", annotation.forceNewActivity())
|
||||
/*---*/.add(",")
|
||||
/*---*/.add("$S", annotation.forceNewActivityKey())
|
||||
/*---*/.add(",")
|
||||
/*---*/.add("required")
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(intParam)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(boolParam)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(longParam)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(floatParam)
|
||||
/*---*/.add(",")
|
||||
/*---*/.add(doubleParam)
|
||||
/**/.add(")")
|
||||
.add(")")
|
||||
.build();
|
||||
constructorBuilder.addStatement(codeBlock);
|
||||
}
|
||||
}
|
||||
|
||||
constructorBuilder.addStatement("mSchemeMap.put($S, elements)", key);
|
||||
}
|
||||
|
||||
ExecutableElement findScheme = getOverrideMethod(
|
||||
SchemeMap, "findScheme");
|
||||
List<? extends VariableElement> findSchemeParams = findScheme.getParameters();
|
||||
String schemeAction = findSchemeParams.get(0).getSimpleName().toString();
|
||||
String schemeParam = findSchemeParams.get(1).getSimpleName().toString();
|
||||
MethodSpec.Builder getRecordMetaById = MethodSpec.overriding(findScheme)
|
||||
.addStatement("$T list = mSchemeMap.get($L)", SchemeItemList, schemeAction)
|
||||
.beginControlFlow("if(list == null || list.isEmpty())")
|
||||
/**/.addStatement("return null")
|
||||
.endControlFlow()
|
||||
.beginControlFlow("for (int i = 0; i < list.size(); i++)")
|
||||
/**/.addStatement("$T item = list.get(i)", SchemeItem)
|
||||
/**/.beginControlFlow("if(item.match($L))", schemeParam)
|
||||
/*--*/.addStatement("return item")
|
||||
/**/.endControlFlow()
|
||||
.endControlFlow()
|
||||
.addStatement("return null");
|
||||
ExecutableElement exists = getOverrideMethod(
|
||||
SchemeMap, "exists");
|
||||
MethodSpec.Builder getRecordMetaByClass = MethodSpec.overriding(exists)
|
||||
.addStatement("return mSchemeMap.containsKey($L)", exists.getParameters().get(0).getSimpleName().toString());
|
||||
|
||||
classBuilder
|
||||
.addMethod(constructorBuilder.build())
|
||||
.addMethod(getRecordMetaById.build())
|
||||
.addMethod(getRecordMetaByClass.build());
|
||||
try {
|
||||
JavaFile.builder(SchemeMap.packageName(), classBuilder.build())
|
||||
.build().writeTo(mFiler);
|
||||
} catch (IOException e) {
|
||||
error(null, "Unable to generate RecordMetaMapImpl: %s", e.getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void appendRequired(MethodSpec.Builder constructorBuilder, String[] required) {
|
||||
if (required == null || required.length == 0) {
|
||||
constructorBuilder.addStatement("required =null");
|
||||
return;
|
||||
}
|
||||
constructorBuilder.addStatement("required = new $T<>()", ArrayMapName);
|
||||
for (int i = 0; i < required.length; i++) {
|
||||
String condition = required[i];
|
||||
if (condition == null || condition.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
int index = condition.indexOf("=");
|
||||
if (index < 0 || index >= condition.length()) {
|
||||
constructorBuilder.addStatement("required.put($S, null)", condition);
|
||||
} else {
|
||||
String key = condition.substring(0, index);
|
||||
String value = index == condition.length() - 1 ? "" : condition.substring(index + 1);
|
||||
constructorBuilder.addStatement("required.put($S, $S)", key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private CodeBlock generateTypedParams(String[] keys) {
|
||||
CodeBlock.Builder builder = CodeBlock.builder();
|
||||
if (keys == null || keys.length == 0) {
|
||||
builder.add("null");
|
||||
} else {
|
||||
builder.add("new $T[]{", StringName);
|
||||
for (int i = 0; i < keys.length; i++) {
|
||||
if (i != 0) {
|
||||
builder.add(",");
|
||||
}
|
||||
builder.add("$S", keys[i]);
|
||||
}
|
||||
builder.add("}");
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
private CodeBlock generateCustomFactory(boolean isActivity, AnnotationMirror annotationMirror){
|
||||
AnnotationValue customFactory = getAnnotationValue(annotationMirror, "customFactory");
|
||||
if (customFactory == null) {
|
||||
return CodeBlock.of("null");
|
||||
}
|
||||
TypeMirror typeMirror = (TypeMirror) customFactory.getValue();
|
||||
if(isActivity){
|
||||
if (!isSubtypeOfType(typeMirror, QMUISchemeIntentFactoryType)) {
|
||||
throw new IllegalStateException("customFactory must implement interface QMUISchemeIntentFactory.");
|
||||
}
|
||||
}else{
|
||||
if (!isSubtypeOfType(typeMirror, QMUISchemeFragmentFactoryType)) {
|
||||
throw new IllegalStateException("customFactory must implement interface QMUISchemeFragmentFactory.");
|
||||
}
|
||||
}
|
||||
|
||||
return CodeBlock.of("$T.class", typeMirror);
|
||||
}
|
||||
|
||||
private CodeBlock generateFragmentHostActivityList(FragmentScheme fragmentScheme){
|
||||
CodeBlock.Builder builder = CodeBlock.builder();
|
||||
TypeMirror[] activities = null;
|
||||
try {
|
||||
fragmentScheme.activities();
|
||||
} catch (MirroredTypesException mte) {
|
||||
List<? extends TypeMirror> containerMirrors = mte.getTypeMirrors();
|
||||
activities = new TypeMirror[containerMirrors.size()];
|
||||
for (int i = 0; i < activities.length; i++) {
|
||||
activities[i] = containerMirrors.get(i);
|
||||
}
|
||||
}
|
||||
if(activities == null || activities.length == 0){
|
||||
throw new IllegalStateException("FragmentScheme#activities can not be empty.");
|
||||
}
|
||||
builder.add("new $T[]{", OriginClassName);
|
||||
for(int i=0; i < activities.length; i++){
|
||||
TypeMirror item = activities[i];
|
||||
if(!isSubtypeOfType(item, QMUI_FRAGMENT_ACTIVITY_TYPE)){
|
||||
throw new IllegalStateException("FragmentScheme#activities must be QMUIFragmentActivity.");
|
||||
}
|
||||
if(i > 0){
|
||||
builder.add(",");
|
||||
}
|
||||
builder.add("$T.class", ClassName.get(item));
|
||||
}
|
||||
builder.add("}");
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getSupportedAnnotationTypes() {
|
||||
Set<String> types = new LinkedHashSet<>();
|
||||
types.add(ActivityScheme.class.getCanonicalName());
|
||||
types.add(FragmentScheme.class.getCanonicalName());
|
||||
return types;
|
||||
}
|
||||
|
||||
static class Item {
|
||||
boolean isActivity = false;
|
||||
TypeElement element;
|
||||
TypeMirror type;
|
||||
String[] required;
|
||||
|
||||
public Item(boolean isActivity, TypeElement element, TypeMirror type, String[] required) {
|
||||
this.isActivity = isActivity;
|
||||
this.element = element;
|
||||
this.type = type;
|
||||
this.required = required;
|
||||
}
|
||||
|
||||
int getRequiredCount(){
|
||||
return required == null ? 0 : required.length;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,8 +321,8 @@ public abstract class QMUIFragment extends Fragment implements
|
||||
* @param useNewTransitionConfigWhenPop if true, use animation generated by transition C->D,
|
||||
* else, use animation generated by transition B->C
|
||||
*/
|
||||
protected int startFragmentAndDestroyCurrent(final QMUIFragment fragment,
|
||||
final boolean useNewTransitionConfigWhenPop) {
|
||||
protected int startFragmentAndDestroyCurrent(QMUIFragment fragment,
|
||||
boolean useNewTransitionConfigWhenPop) {
|
||||
if (!checkStateLoss("startFragmentAndDestroyCurrent")) {
|
||||
return -1;
|
||||
}
|
||||
@@ -337,7 +337,7 @@ public abstract class QMUIFragment extends Fragment implements
|
||||
}
|
||||
}
|
||||
|
||||
final QMUIFragment.TransitionConfig transitionConfig = fragment.onFetchTransitionConfig();
|
||||
QMUIFragment.TransitionConfig transitionConfig = fragment.onFetchTransitionConfig();
|
||||
String tagName = fragment.getClass().getSimpleName();
|
||||
FragmentManager fragmentManager = provider.getContainerFragmentManager();
|
||||
FragmentTransaction transaction = fragmentManager.beginTransaction()
|
||||
@@ -346,52 +346,7 @@ public abstract class QMUIFragment extends Fragment implements
|
||||
transitionConfig.popenter, transitionConfig.popout)
|
||||
.replace(provider.getContextViewId(), fragment, tagName);
|
||||
int index = transaction.commit();
|
||||
Utils.findAndModifyOpInBackStackRecord(fragmentManager, -1, new Utils.OpHandler() {
|
||||
@Override
|
||||
public boolean handle(Object op) {
|
||||
Field cmdField = null;
|
||||
try {
|
||||
cmdField = Utils.getOpCmdField(op);
|
||||
cmdField.setAccessible(true);
|
||||
int cmd = (int) cmdField.get(op);
|
||||
if (cmd == 1) {
|
||||
if (useNewTransitionConfigWhenPop) {
|
||||
Field popEnterAnimField = Utils.getOpPopEnterAnimField(op);
|
||||
popEnterAnimField.setAccessible(true);
|
||||
popEnterAnimField.set(op, transitionConfig.popenter);
|
||||
|
||||
Field popExitAnimField = Utils.getOpPopExitAnimField(op);
|
||||
popExitAnimField.setAccessible(true);
|
||||
popExitAnimField.set(op, transitionConfig.popout);
|
||||
}
|
||||
|
||||
Field oldFragmentField = Utils.getOpFragmentField(op);
|
||||
oldFragmentField.setAccessible(true);
|
||||
Object fragmentObj = oldFragmentField.get(op);
|
||||
oldFragmentField.set(op, fragment);
|
||||
Field backStackNestField = Fragment.class.getDeclaredField("mBackStackNesting");
|
||||
backStackNestField.setAccessible(true);
|
||||
int oldFragmentBackStackNest = (int) backStackNestField.get(fragmentObj);
|
||||
backStackNestField.set(fragment, oldFragmentBackStackNest);
|
||||
backStackNestField.set(fragmentObj, --oldFragmentBackStackNest);
|
||||
return true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needReNameTag() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String newTagName() {
|
||||
return fragment.getClass().getSimpleName();
|
||||
}
|
||||
});
|
||||
Utils.modifyOpForStartFragmentAndDestroyCurrent(fragmentManager, fragment, useNewTransitionConfigWhenPop, transitionConfig);
|
||||
return index;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,8 +44,6 @@ import com.qmuiteam.qmui.util.QMUIStatusBarHelper;
|
||||
import com.qmuiteam.qmui.util.QMUIWindowInsetHelper;
|
||||
import com.qmuiteam.qmui.widget.QMUIWindowInsetLayout;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
/**
|
||||
* the container activity for {@link QMUIFragment}.
|
||||
* Created by cgspine on 15/9/14.
|
||||
@@ -217,67 +215,22 @@ public abstract class QMUIFragmentActivity extends InnerBaseActivity implements
|
||||
* @param fragment new fragment to start
|
||||
* @param useNewTransitionConfigWhenPop if true, use animation generated by transition C->D,
|
||||
* else, use animation generated by transition B->C
|
||||
*
|
||||
* @deprecated use {@link QMUIFragment#startFragmentAndDestroyCurrent(QMUIFragment, boolean)}
|
||||
*/
|
||||
@Deprecated
|
||||
public int startFragmentAndDestroyCurrent(final QMUIFragment fragment, final boolean useNewTransitionConfigWhenPop) {
|
||||
final QMUIFragment.TransitionConfig transitionConfig = fragment.onFetchTransitionConfig();
|
||||
String tagName = fragment.getClass().getSimpleName();
|
||||
|
||||
public int startFragmentAndDestroyCurrent(QMUIFragment fragment, final boolean useNewTransitionConfigWhenPop) {
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
if (fragmentManager.isStateSaved()) {
|
||||
QMUILog.d(TAG, "startFragment can not be invoked after onSaveInstanceState");
|
||||
return -1;
|
||||
}
|
||||
QMUIFragment.TransitionConfig transitionConfig = fragment.onFetchTransitionConfig();
|
||||
String tagName = fragment.getClass().getSimpleName();
|
||||
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction()
|
||||
.setCustomAnimations(transitionConfig.enter, transitionConfig.exit,
|
||||
transitionConfig.popenter, transitionConfig.popout)
|
||||
.replace(getContextViewId(), fragment, tagName);
|
||||
int index = transaction.commit();
|
||||
Utils.findAndModifyOpInBackStackRecord(fragmentManager, -1, new Utils.OpHandler() {
|
||||
@Override
|
||||
public boolean handle(Object op) {
|
||||
Field cmdField = null;
|
||||
try {
|
||||
cmdField = Utils.getOpCmdField(op);
|
||||
cmdField.setAccessible(true);
|
||||
int cmd = (int) cmdField.get(op);
|
||||
if (cmd == 1) {
|
||||
if (useNewTransitionConfigWhenPop) {
|
||||
Field popEnterAnimField = Utils.getOpPopEnterAnimField(op);
|
||||
popEnterAnimField.setAccessible(true);
|
||||
popEnterAnimField.set(op, transitionConfig.popenter);
|
||||
|
||||
Field popExitAnimField = Utils.getOpPopExitAnimField(op);
|
||||
popExitAnimField.setAccessible(true);
|
||||
popExitAnimField.set(op, transitionConfig.popout);
|
||||
}
|
||||
|
||||
Field oldFragmentField = Utils.getOpFragmentField(op);
|
||||
oldFragmentField.setAccessible(true);
|
||||
Object fragmentObj = oldFragmentField.get(op);
|
||||
oldFragmentField.set(op, fragment);
|
||||
Field backStackNestField = Fragment.class.getDeclaredField("mBackStackNesting");
|
||||
backStackNestField.setAccessible(true);
|
||||
int oldFragmentBackStackNest = (int) backStackNestField.get(fragmentObj);
|
||||
backStackNestField.set(fragment, oldFragmentBackStackNest);
|
||||
backStackNestField.set(fragmentObj, --oldFragmentBackStackNest);
|
||||
return true;
|
||||
}
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needReNameTag() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String newTagName() {
|
||||
return fragment.getClass().getSimpleName();
|
||||
}
|
||||
});
|
||||
Utils.modifyOpForStartFragmentAndDestroyCurrent(fragmentManager, fragment, useNewTransitionConfigWhenPop, transitionConfig);
|
||||
return index;
|
||||
}
|
||||
|
||||
@@ -286,15 +239,17 @@ public abstract class QMUIFragmentActivity extends InnerBaseActivity implements
|
||||
* @param fragment target fragment to start
|
||||
* @return commit id
|
||||
*
|
||||
* @deprecated use {@link QMUIFragment#startFragment(QMUIFragment)}
|
||||
*/
|
||||
@Deprecated
|
||||
public int startFragment(QMUIFragment fragment) {
|
||||
Log.i(TAG, "startFragment");
|
||||
FragmentManager fragmentManager = getSupportFragmentManager();
|
||||
if (fragmentManager.isStateSaved()) {
|
||||
QMUILog.d(TAG, "startFragment can not be invoked after onSaveInstanceState");
|
||||
return -1;
|
||||
}
|
||||
QMUIFragment.TransitionConfig transitionConfig = fragment.onFetchTransitionConfig();
|
||||
String tagName = fragment.getClass().getSimpleName();
|
||||
return getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
return fragmentManager.beginTransaction()
|
||||
.setCustomAnimations(transitionConfig.enter, transitionConfig.exit, transitionConfig.popenter, transitionConfig.popout)
|
||||
.replace(getContextViewId(), fragment, tagName)
|
||||
.addToBackStack(tagName)
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.util.Stack;
|
||||
public class QMUISwipeBackActivityManager implements Application.ActivityLifecycleCallbacks {
|
||||
private static QMUISwipeBackActivityManager sInstance;
|
||||
private Stack<Activity> mActivityStack = new Stack<>();
|
||||
private Activity mCurrentActivity = null;
|
||||
|
||||
|
||||
@MainThread
|
||||
@@ -51,41 +52,45 @@ public class QMUISwipeBackActivityManager implements Application.ActivityLifecyc
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||
public void onActivityCreated(@NonNull Activity activity, Bundle savedInstanceState) {
|
||||
mActivityStack.add(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityDestroyed(Activity activity) {
|
||||
public void onActivityDestroyed(@NonNull Activity activity) {
|
||||
mActivityStack.remove(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStarted(Activity activity) {
|
||||
public void onActivityStarted(@NonNull Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed(Activity activity) {
|
||||
public void onActivityResumed(@NonNull Activity activity) {
|
||||
mCurrentActivity = activity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(@NonNull Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(Activity activity) {
|
||||
public void onActivityStopped(@NonNull Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityStopped(Activity activity) {
|
||||
public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
|
||||
|
||||
@Nullable
|
||||
public Activity getCurrentActivity(){
|
||||
return mCurrentActivity;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* refer to https://github.com/bingoogolapple/BGASwipeBackLayout-Android/
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.List;
|
||||
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
|
||||
@@ -138,6 +139,58 @@ public class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
static void modifyOpForStartFragmentAndDestroyCurrent(FragmentManager fragmentManager,
|
||||
final QMUIFragment fragment,
|
||||
final boolean useNewTransitionConfigWhenPop,
|
||||
final QMUIFragment.TransitionConfig transitionConfig){
|
||||
findAndModifyOpInBackStackRecord(fragmentManager, -1, new Utils.OpHandler() {
|
||||
@Override
|
||||
public boolean handle(Object op) {
|
||||
Field cmdField = null;
|
||||
try {
|
||||
cmdField = Utils.getOpCmdField(op);
|
||||
cmdField.setAccessible(true);
|
||||
int cmd = (int) cmdField.get(op);
|
||||
if (cmd == 1) {
|
||||
if (useNewTransitionConfigWhenPop) {
|
||||
Field popEnterAnimField = Utils.getOpPopEnterAnimField(op);
|
||||
popEnterAnimField.setAccessible(true);
|
||||
popEnterAnimField.set(op, transitionConfig.popenter);
|
||||
|
||||
Field popExitAnimField = Utils.getOpPopExitAnimField(op);
|
||||
popExitAnimField.setAccessible(true);
|
||||
popExitAnimField.set(op, transitionConfig.popout);
|
||||
}
|
||||
|
||||
Field oldFragmentField = Utils.getOpFragmentField(op);
|
||||
oldFragmentField.setAccessible(true);
|
||||
Object fragmentObj = oldFragmentField.get(op);
|
||||
oldFragmentField.set(op, fragment);
|
||||
Field backStackNestField = Fragment.class.getDeclaredField("mBackStackNesting");
|
||||
backStackNestField.setAccessible(true);
|
||||
int oldFragmentBackStackNest = (int) backStackNestField.get(fragmentObj);
|
||||
backStackNestField.set(fragment, oldFragmentBackStackNest);
|
||||
backStackNestField.set(fragmentObj, --oldFragmentBackStackNest);
|
||||
return true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean needReNameTag() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String newTagName() {
|
||||
return fragment.getClass().getSimpleName();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void findAndModifyOpInBackStackRecord(FragmentManager fragmentManager, int backStackIndex, OpHandler handler) {
|
||||
if (fragmentManager == null || handler == null) {
|
||||
return;
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.scheme;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.qmuiteam.qmui.QMUILog;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
class ActivitySchemeItem extends SchemeItem {
|
||||
private static HashMap<Class<? extends QMUISchemeIntentFactory>, QMUISchemeIntentFactory> sFactories;
|
||||
|
||||
@NonNull
|
||||
private final Class<? extends Activity> mActivityClass;
|
||||
@NonNull
|
||||
private final Class<? extends QMUISchemeIntentFactory> mIntentFactoryCls;
|
||||
|
||||
public ActivitySchemeItem(@NonNull Class<? extends Activity> activityClass,
|
||||
@Nullable Class<? extends QMUISchemeIntentFactory> intentFactoryCls,
|
||||
@Nullable ArrayMap<String, String> required,
|
||||
@Nullable String[] keysForInt,
|
||||
@Nullable String[] keysForBool,
|
||||
@Nullable String[] keysForLong,
|
||||
@Nullable String[] keysForFloat,
|
||||
@Nullable String[] keysForDouble) {
|
||||
super(required, keysForInt, keysForBool, keysForLong, keysForFloat, keysForDouble);
|
||||
mActivityClass = activityClass;
|
||||
if (intentFactoryCls == null) {
|
||||
mIntentFactoryCls = QMUIDefaultSchemeIntentFactory.class;
|
||||
} else {
|
||||
mIntentFactoryCls = intentFactoryCls;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(@NonNull Activity activity, @NonNull Map<String, SchemeValue> scheme) {
|
||||
if (sFactories == null) {
|
||||
sFactories = new HashMap<>();
|
||||
}
|
||||
QMUISchemeIntentFactory factory = sFactories.get(mIntentFactoryCls);
|
||||
if (factory == null) {
|
||||
try {
|
||||
factory = mIntentFactoryCls.newInstance();
|
||||
sFactories.put(mIntentFactoryCls, factory);
|
||||
} catch (Exception e) {
|
||||
QMUILog.printErrStackTrace(QMUISchemeHandler.TAG, e,
|
||||
"error to instance QMUISchemeIntentFactory: %d", mIntentFactoryCls.getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
if (factory != null) {
|
||||
|
||||
if (factory.shouldBlockJump(activity, mActivityClass, scheme)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Intent intent = factory.factory(activity, mActivityClass, scheme);
|
||||
activity.startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.scheme;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.qmuiteam.qmui.QMUILog;
|
||||
import com.qmuiteam.qmui.arch.QMUIFragment;
|
||||
import com.qmuiteam.qmui.arch.QMUIFragmentActivity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
class FragmentSchemeItem extends SchemeItem {
|
||||
private static HashMap<Class<? extends QMUISchemeFragmentFactory>, QMUISchemeFragmentFactory> sFactories;
|
||||
private final Class<? extends QMUIFragment> mFragmentCls;
|
||||
@NonNull
|
||||
private final Class<? extends QMUIFragmentActivity>[] mActivityClsList;
|
||||
private final boolean mForceNewActivity;
|
||||
private final String mForceNewActivityKey;
|
||||
@NonNull
|
||||
private final Class<? extends QMUISchemeFragmentFactory> mFragmentFactoryCls;
|
||||
|
||||
public FragmentSchemeItem(@NonNull Class<? extends QMUIFragment> fragmentCls,
|
||||
@NonNull Class<? extends QMUIFragmentActivity>[] activityClsList,
|
||||
@Nullable Class<? extends QMUISchemeFragmentFactory> fragmentFactoryCls,
|
||||
boolean forceNewActivity,
|
||||
@Nullable String forceNewActivityKey,
|
||||
@Nullable ArrayMap<String, String> required,
|
||||
@Nullable String[] keysForInt,
|
||||
@Nullable String[] keysForBool,
|
||||
@Nullable String[] keysForLong,
|
||||
@Nullable String[] keysForFloat,
|
||||
@Nullable String[] keysForDouble) {
|
||||
super(required, keysForInt, keysForBool, keysForLong, keysForFloat, keysForDouble);
|
||||
mFragmentCls = fragmentCls;
|
||||
mActivityClsList = activityClsList;
|
||||
mForceNewActivity = forceNewActivity;
|
||||
mForceNewActivityKey = forceNewActivityKey;
|
||||
if(fragmentFactoryCls == null){
|
||||
mFragmentFactoryCls = QMUIDefaultSchemeFragmentFactory.class;
|
||||
}else{
|
||||
mFragmentFactoryCls = fragmentFactoryCls;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean handle(@NonNull Activity activity, @Nullable Map<String, SchemeValue> scheme) {
|
||||
if (mActivityClsList.length == 0) {
|
||||
QMUILog.d(QMUISchemeHandler.TAG, "Can not start a new fragment because the host is't provided");
|
||||
return false;
|
||||
}
|
||||
if (sFactories == null) {
|
||||
sFactories = new HashMap<>();
|
||||
}
|
||||
QMUISchemeFragmentFactory factory = sFactories.get(mFragmentFactoryCls);
|
||||
if (factory == null) {
|
||||
try {
|
||||
factory = mFragmentFactoryCls.newInstance();
|
||||
sFactories.put(mFragmentFactoryCls, factory);
|
||||
} catch (Exception e) {
|
||||
QMUILog.printErrStackTrace(QMUISchemeHandler.TAG, e,
|
||||
"error to instance QMUISchemeFragmentFactory: %d", mFragmentFactoryCls.getSimpleName());
|
||||
}
|
||||
}
|
||||
if (factory == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(factory.shouldBlockJump(activity, mFragmentCls, scheme)){
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!isCurrentActivityCanStartFragment(activity) || isForceNewActivity(scheme)) {
|
||||
Intent intent = factory.factory(activity, mActivityClsList, mFragmentCls, scheme);
|
||||
if (intent != null) {
|
||||
activity.startActivity(intent);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QMUIFragmentActivity fragmentActivity = (QMUIFragmentActivity) activity;
|
||||
QMUIFragment fragment = factory.factory(mFragmentCls, scheme);
|
||||
if (fragment != null) {
|
||||
int commitId = fragmentActivity.startFragment(fragment);
|
||||
if (commitId == -1) {
|
||||
QMUILog.d(QMUISchemeHandler.TAG, "start fragment failed.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isCurrentActivityCanStartFragment(Activity activity) {
|
||||
if (!(activity instanceof QMUIFragmentActivity)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QMUIFragmentActivity fragmentActivity = (QMUIFragmentActivity) activity;
|
||||
if (fragmentActivity.getSupportFragmentManager().isStateSaved()) {
|
||||
// use new activity if the state has already been saved.
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Class<? extends QMUIFragmentActivity> aClass : mActivityClsList) {
|
||||
if (aClass.isAssignableFrom(activity.getClass())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isForceNewActivity(@Nullable Map<String, SchemeValue> scheme) {
|
||||
if (mForceNewActivity) {
|
||||
return true;
|
||||
}
|
||||
if (scheme == null || scheme.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
if (scheme.get(QMUISchemeHandler.ARG_FORCE_TO_NEW_ACTIVITY) != null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mForceNewActivityKey != null) {
|
||||
SchemeValue schemeValue = scheme.get(mForceNewActivityKey);
|
||||
return schemeValue != null && schemeValue.type == Boolean.TYPE && ((Boolean) schemeValue.value);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.scheme;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.qmuiteam.qmui.QMUILog;
|
||||
import com.qmuiteam.qmui.arch.QMUIFragment;
|
||||
import com.qmuiteam.qmui.arch.QMUIFragmentActivity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.qmuiteam.qmui.arch.scheme.QMUISchemeHandler.ARG_FROM_SCHEME;
|
||||
|
||||
public class QMUIDefaultSchemeFragmentFactory implements QMUISchemeFragmentFactory {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public QMUIFragment factory(@NonNull Class<? extends QMUIFragment> fragmentCls,
|
||||
@Nullable Map<String, SchemeValue> scheme) {
|
||||
try {
|
||||
QMUIFragment fragment = fragmentCls.newInstance();
|
||||
fragment.setArguments(createBundleForScheme(scheme));
|
||||
return fragment;
|
||||
} catch (Exception e) {
|
||||
QMUILog.printErrStackTrace(QMUISchemeHandler.TAG, e,
|
||||
"Error to create fragment: %s", fragmentCls.getSimpleName());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Intent factory(@NonNull Activity activity,
|
||||
@NonNull Class<? extends QMUIFragmentActivity>[] activityClassList,
|
||||
@NonNull Class<? extends QMUIFragment> fragmentCls,
|
||||
@Nullable Map<String, SchemeValue> scheme) {
|
||||
Bundle bundle = createBundleForScheme(scheme);
|
||||
if (activityClassList.length == 0) {
|
||||
return null;
|
||||
}
|
||||
Intent intent = QMUIFragmentActivity.intentOf(activity, activityClassList[0], fragmentCls, bundle);
|
||||
intent.putExtra(ARG_FROM_SCHEME, true);
|
||||
return intent;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Bundle createBundleForScheme(@Nullable Map<String, SchemeValue> scheme) {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBoolean(QMUISchemeHandler.ARG_FROM_SCHEME, true);
|
||||
if (scheme != null && !scheme.isEmpty()) {
|
||||
for (Map.Entry<String, SchemeValue> item : scheme.entrySet()) {
|
||||
String name = item.getKey();
|
||||
SchemeValue schemeValue = item.getValue();
|
||||
if (schemeValue.type == Integer.TYPE) {
|
||||
bundle.putInt(name, ((int) schemeValue.value));
|
||||
} else if (schemeValue.type == Boolean.TYPE) {
|
||||
bundle.putBoolean(name, ((boolean) schemeValue.value));
|
||||
} else if (schemeValue.type == Long.TYPE) {
|
||||
bundle.putLong(name, ((long) schemeValue.value));
|
||||
} else if (schemeValue.type == Float.TYPE) {
|
||||
bundle.putFloat(name, ((float) schemeValue.value));
|
||||
} else if (schemeValue.type == Double.TYPE) {
|
||||
bundle.putDouble(name, ((double) schemeValue.value));
|
||||
} else {
|
||||
bundle.putString(name, schemeValue.origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldBlockJump(@NonNull Activity activity,
|
||||
@NonNull Class<? extends QMUIFragment> fragmentCls,
|
||||
@Nullable Map<String, SchemeValue> scheme) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.scheme;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static com.qmuiteam.qmui.arch.scheme.QMUISchemeHandler.ARG_FROM_SCHEME;
|
||||
|
||||
public class QMUIDefaultSchemeIntentFactory implements QMUISchemeIntentFactory {
|
||||
@Override
|
||||
public Intent factory(@NonNull Activity activity,
|
||||
@NonNull Class<? extends Activity> activityClass,
|
||||
@Nullable Map<String, SchemeValue> scheme) {
|
||||
Intent intent = new Intent(activity, activityClass);
|
||||
intent.putExtra(ARG_FROM_SCHEME, true);
|
||||
if (scheme != null && !scheme.isEmpty()) {
|
||||
for (Map.Entry<String, SchemeValue> item : scheme.entrySet()) {
|
||||
String name = item.getKey();
|
||||
SchemeValue schemeValue = item.getValue();
|
||||
if (schemeValue.type == Integer.TYPE) {
|
||||
intent.putExtra(name, ((int) schemeValue.value));
|
||||
} else if (schemeValue.type == Boolean.TYPE) {
|
||||
intent.putExtra(name, ((boolean) schemeValue.value));
|
||||
} else if (schemeValue.type == Long.TYPE) {
|
||||
intent.putExtra(name, ((long) schemeValue.value));
|
||||
} else if (schemeValue.type == Float.TYPE) {
|
||||
intent.putExtra(name, ((float) schemeValue.value));
|
||||
} else if (schemeValue.type == Double.TYPE) {
|
||||
intent.putExtra(name, ((double) schemeValue.value));
|
||||
} else {
|
||||
intent.putExtra(name, schemeValue.origin);
|
||||
}
|
||||
}
|
||||
}
|
||||
return intent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldBlockJump(@NonNull Activity activity,
|
||||
@NonNull Class<? extends Activity> activityClass,
|
||||
@Nullable Map<String, SchemeValue> scheme) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.scheme;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.qmuiteam.qmui.arch.QMUIFragment;
|
||||
import com.qmuiteam.qmui.arch.QMUIFragmentActivity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface QMUISchemeFragmentFactory {
|
||||
@Nullable
|
||||
QMUIFragment factory(@NonNull Class<? extends QMUIFragment> fragmentCls,
|
||||
@Nullable Map<String, SchemeValue> scheme);
|
||||
|
||||
@Nullable
|
||||
Intent factory(@NonNull Activity activity,
|
||||
@NonNull Class<? extends QMUIFragmentActivity>[] activityClassList,
|
||||
@NonNull Class<? extends QMUIFragment> fragmentCls,
|
||||
@Nullable Map<String, SchemeValue> scheme);
|
||||
|
||||
boolean shouldBlockJump(@NonNull Activity activity,
|
||||
@NonNull Class<? extends QMUIFragment> fragmentCls,
|
||||
@Nullable Map<String, SchemeValue> scheme);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.scheme;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface QMUISchemeHandleInterpolator {
|
||||
boolean intercept(Activity activity, String action, Map<String, String> params, String origin);
|
||||
}
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.scheme;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.util.Pair;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.qmuiteam.qmui.arch.QMUISwipeBackActivityManager;
|
||||
import com.qmuiteam.qmui.arch.record.QMUILatestVisitStorage;
|
||||
import com.qmuiteam.qmui.arch.record.RecordIdClassMap;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class QMUISchemeHandler {
|
||||
static final String TAG = "QMUISchemeHandler";
|
||||
public static String ARG_FROM_SCHEME = "__qmui_arg_from_scheme";
|
||||
public static String ARG_FORCE_TO_NEW_ACTIVITY = "__qmui_force_to_new_activity";
|
||||
|
||||
private static SchemeMap sSchemeMap;
|
||||
|
||||
static {
|
||||
try {
|
||||
Class<?> cls = Class.forName(SchemeMap.class.getCanonicalName() + "Impl");
|
||||
sSchemeMap = (SchemeMap) cls.newInstance();
|
||||
} catch (ClassNotFoundException e) {
|
||||
sSchemeMap = new SchemeMap() {
|
||||
@Nullable
|
||||
@Override
|
||||
public SchemeItem findScheme(@NonNull String schemeName, @Nullable Map<String, String> params) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean exists(@NonNull String schemeName) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException("Can not access the Class SchemeMapImpl. " +
|
||||
"Please file a issue to report this.");
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException("Can not instance the Class SchemeMapImpl. " +
|
||||
"Please file a issue to report this.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private final String mPrefix;
|
||||
private final List<QMUISchemeHandleInterpolator> mInterpolatorList;
|
||||
private final long mBlockSameSchemeTimeout;
|
||||
private String mLastHandledScheme = null;
|
||||
private long mLastSchemeHandledTime = 0;
|
||||
|
||||
private QMUISchemeHandler(Builder builder) {
|
||||
mPrefix = builder.mPrefix;
|
||||
List<QMUISchemeHandleInterpolator> interpolatorList = builder.mInterpolatorList;
|
||||
if(interpolatorList != null && !interpolatorList.isEmpty()){
|
||||
mInterpolatorList = new ArrayList<>(interpolatorList);
|
||||
}else{
|
||||
mInterpolatorList = null;
|
||||
}
|
||||
mBlockSameSchemeTimeout = builder.mBlockSameSchemeTimeout;
|
||||
}
|
||||
|
||||
public boolean handle(String scheme){
|
||||
if(scheme == null || !scheme.startsWith(mPrefix)){
|
||||
return false;
|
||||
}
|
||||
|
||||
if(scheme.equals(mLastHandledScheme) && System.currentTimeMillis() - mLastSchemeHandledTime < mBlockSameSchemeTimeout){
|
||||
return true;
|
||||
}
|
||||
|
||||
Activity currentActivity = QMUISwipeBackActivityManager.getInstance().getCurrentActivity();
|
||||
if(currentActivity == null){
|
||||
return false;
|
||||
}
|
||||
|
||||
scheme = scheme.substring(mPrefix.length());
|
||||
String[] elements = scheme.split("\\?");
|
||||
if(elements.length == 0 || elements[0] == null || elements[0].isEmpty()){
|
||||
return false;
|
||||
}
|
||||
String action = elements[0];
|
||||
if(!sSchemeMap.exists(action)){
|
||||
return false;
|
||||
}
|
||||
|
||||
Map<String, String> params;
|
||||
if(elements.length < 2){
|
||||
params = null;
|
||||
}else{
|
||||
params = parseParams(elements[1]);
|
||||
}
|
||||
|
||||
boolean handled = false;
|
||||
if(mInterpolatorList != null && !mInterpolatorList.isEmpty()){
|
||||
for(QMUISchemeHandleInterpolator interpolator: mInterpolatorList){
|
||||
if(interpolator.intercept(currentActivity, action, params, scheme)){
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!handled){
|
||||
SchemeItem schemeItem = sSchemeMap.findScheme(action, params);
|
||||
if(schemeItem != null){
|
||||
handled = schemeItem.handle(currentActivity, schemeItem.convertFrom(params));
|
||||
}
|
||||
}
|
||||
|
||||
if(handled){
|
||||
mLastHandledScheme = scheme;
|
||||
mLastSchemeHandledTime = System.currentTimeMillis();
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Map<String, String> parseParams(@Nullable String schemeParams) {
|
||||
if (schemeParams == null || schemeParams.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, String> queryMap = new HashMap<>();
|
||||
int start = 0;
|
||||
do {
|
||||
int next = schemeParams.indexOf('&', start);
|
||||
int end = (next == -1) ? schemeParams.length() : next;
|
||||
if (start == end) {
|
||||
start += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
int separator = schemeParams.indexOf('=', start);
|
||||
if (separator > end || separator == -1) {
|
||||
separator = end;
|
||||
}
|
||||
if (separator == start) {
|
||||
start = end + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
String name = schemeParams.substring(start, separator);
|
||||
String value = separator == end ? "" : schemeParams.substring(separator + 1, end);
|
||||
queryMap.put(name, value);
|
||||
start = end + 1;
|
||||
} while (start < schemeParams.length());
|
||||
return queryMap;
|
||||
}
|
||||
|
||||
|
||||
public static class Builder {
|
||||
public static final long BLOCK_SAME_SCHEME_DEFAULT_TIMEOUT = 500;
|
||||
private String mPrefix;
|
||||
private List<QMUISchemeHandleInterpolator> mInterpolatorList;
|
||||
private long mBlockSameSchemeTimeout = BLOCK_SAME_SCHEME_DEFAULT_TIMEOUT;
|
||||
|
||||
public Builder(@NonNull String prefix) {
|
||||
mPrefix = prefix;
|
||||
}
|
||||
|
||||
public Builder addInterpolator(QMUISchemeHandleInterpolator interpolator) {
|
||||
if(mInterpolatorList == null){
|
||||
mInterpolatorList = new ArrayList<>();
|
||||
}
|
||||
mInterpolatorList.add(interpolator);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setBlockSameSchemeTimeout(long blockSameSchemeTimeout) {
|
||||
mBlockSameSchemeTimeout = blockSameSchemeTimeout;
|
||||
return this;
|
||||
}
|
||||
|
||||
public QMUISchemeHandler build() {
|
||||
return new QMUISchemeHandler(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.scheme;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface QMUISchemeIntentFactory {
|
||||
Intent factory(@NonNull Activity activity,
|
||||
@NonNull Class<? extends Activity> activityClass,
|
||||
@Nullable Map<String, SchemeValue> scheme);
|
||||
|
||||
boolean shouldBlockJump(@NonNull Activity activity,
|
||||
@NonNull Class<? extends Activity> activityClass,
|
||||
@Nullable Map<String, SchemeValue> scheme);
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.scheme;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class QMUISchemeParamValueDecoder implements QMUISchemeHandleInterpolator {
|
||||
|
||||
@Override
|
||||
public boolean intercept(Activity activity, String action, Map<String, String> params, String origin) {
|
||||
if (params != null) {
|
||||
for (String key : params.keySet()) {
|
||||
String oldValue = params.get(key);
|
||||
if (oldValue != null && oldValue.length() > 0) {
|
||||
params.put(key, Uri.decode(oldValue));
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.scheme;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.util.ArrayMap;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.qmuiteam.qmui.QMUILog;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public abstract class SchemeItem {
|
||||
@Nullable
|
||||
private ArrayMap<String, String> mRequired;
|
||||
@Nullable
|
||||
private String[] mKeysForInt;
|
||||
@Nullable
|
||||
private String[] mKeysForBool;
|
||||
@Nullable
|
||||
private String[] mKeysForLong;
|
||||
@Nullable
|
||||
private String[] mKeysForFloat;
|
||||
@Nullable
|
||||
private String[] mKeysForDouble;
|
||||
|
||||
public SchemeItem(@Nullable ArrayMap<String, String> required,
|
||||
@Nullable String[] keysForInt,
|
||||
@Nullable String[] keysForBool,
|
||||
@Nullable String[] keysForLong,
|
||||
@Nullable String[] keysForFloat,
|
||||
@Nullable String[] keysForDouble) {
|
||||
mRequired = required;
|
||||
mKeysForInt = keysForInt;
|
||||
mKeysForBool = keysForBool;
|
||||
mKeysForLong = keysForLong;
|
||||
mKeysForFloat = keysForFloat;
|
||||
mKeysForDouble = keysForDouble;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Map<String, SchemeValue> convertFrom(@Nullable Map<String, String> schemeParams) {
|
||||
if (schemeParams == null || schemeParams.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Map<String, SchemeValue> queryMap = new HashMap<>();
|
||||
for(Map.Entry<String, String> param: schemeParams.entrySet()){
|
||||
String name = param.getKey();
|
||||
String value = param.getValue();
|
||||
if(name == null || name.isEmpty()){
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
if (contains(mKeysForInt, name)) {
|
||||
queryMap.put(name, new SchemeValue(value, Integer.valueOf(value), Integer.TYPE));
|
||||
} else if (QMUISchemeHandler.ARG_FORCE_TO_NEW_ACTIVITY.equals(name) || contains(mKeysForBool, name)) {
|
||||
boolean isFalse = "0".equals(value) || "false".equals(value.toLowerCase());
|
||||
queryMap.put(name, new SchemeValue(value, !isFalse, Boolean.TYPE));
|
||||
} else if (contains(mKeysForLong, name)) {
|
||||
queryMap.put(name, new SchemeValue(value, Long.valueOf(value), Long.TYPE));
|
||||
} else if (contains(mKeysForFloat, name)) {
|
||||
queryMap.put(name, new SchemeValue(value, Float.valueOf(value), Float.TYPE));
|
||||
} else if (contains(mKeysForDouble, name)) {
|
||||
queryMap.put(name, new SchemeValue(value, Double.valueOf(value), Double.TYPE));
|
||||
} else {
|
||||
queryMap.put(name, new SchemeValue(value, value, String.class));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
QMUILog.printErrStackTrace(QMUISchemeHandler.TAG, e,
|
||||
"error to parse scheme param: %s = %s", name, value);
|
||||
}
|
||||
}
|
||||
return queryMap;
|
||||
}
|
||||
|
||||
private static boolean contains(@Nullable String[] array, @NonNull String key) {
|
||||
if (array == null || array.length == 0) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
if (key.equals(array[i])) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// used by generated code(SchemeMapImpl)
|
||||
boolean match(@Nullable Map<String, String> scheme) {
|
||||
if (mRequired == null || mRequired.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
if (scheme == null || scheme.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < mRequired.size(); i++) {
|
||||
String key = mRequired.keyAt(i);
|
||||
if(!scheme.containsKey(key)){
|
||||
return false;
|
||||
}
|
||||
String value = mRequired.valueAt(i);
|
||||
if(value == null){
|
||||
// if no value. that means scheme must provide this key.
|
||||
continue;
|
||||
}
|
||||
String actual = scheme.get(key);
|
||||
if (actual == null || !actual.equals(value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract boolean handle(@NonNull Activity activity, @Nullable Map<String, SchemeValue> scheme);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.scheme;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface SchemeMap {
|
||||
|
||||
@Nullable
|
||||
SchemeItem findScheme(@NonNull String schemeAction, @Nullable Map<String, String> params);
|
||||
|
||||
boolean exists(@NonNull String schemeAction);
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmui.arch.scheme;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
public class SchemeValue {
|
||||
final String origin;
|
||||
final Object value;
|
||||
final Class<?> type;
|
||||
|
||||
public SchemeValue(@NonNull String origin, Object value, Class<?> type) {
|
||||
this.origin = origin;
|
||||
this.value = value;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ import androidx.core.content.ContextCompat;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import com.qmuiteam.qmui.arch.annotation.ActivityScheme;
|
||||
import com.qmuiteam.qmui.widget.QMUITopBarLayout;
|
||||
import com.qmuiteam.qmuidemo.R;
|
||||
import com.qmuiteam.qmuidemo.base.BaseActivity;
|
||||
@@ -30,6 +31,7 @@ import com.qmuiteam.qmuidemo.fragment.lab.QDArchTestFragment;
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
@ActivityScheme(name = "arch", required = {"aa", "bb=3"}, keysWithBoolValue = {"aa"})
|
||||
public class ArchTestActivity extends BaseActivity {
|
||||
@BindView(R.id.topbar) QMUITopBarLayout mTopBar;
|
||||
|
||||
|
||||
@@ -23,18 +23,20 @@ import android.content.pm.PackageManager;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.qmuiteam.qmui.arch.QMUILatestVisit;
|
||||
import com.qmuiteam.qmuidemo.QDMainActivity;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.ActivityCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
|
||||
import com.qmuiteam.qmui.arch.QMUILatestVisit;
|
||||
import com.qmuiteam.qmui.arch.annotation.ActivityScheme;
|
||||
import com.qmuiteam.qmuidemo.QDMainActivity;
|
||||
|
||||
/**
|
||||
* @author cginechen
|
||||
* @date 2016-12-08
|
||||
*/
|
||||
|
||||
@ActivityScheme(name = "launcher")
|
||||
public class LauncherActivity extends Activity {
|
||||
|
||||
private static final int PERMISSIONS_REQUEST_CODE = 10;
|
||||
@@ -79,9 +81,9 @@ public class LauncherActivity extends Activity {
|
||||
}
|
||||
|
||||
|
||||
private boolean allPermissionsGranted(){
|
||||
for(String permission: PERMISSIONS_REQUIRED){
|
||||
if(ContextCompat.checkSelfPermission(getBaseContext(), permission) != PackageManager.PERMISSION_GRANTED){
|
||||
private boolean allPermissionsGranted() {
|
||||
for (String permission : PERMISSIONS_REQUIRED) {
|
||||
if (ContextCompat.checkSelfPermission(getBaseContext(), permission) != PackageManager.PERMISSION_GRANTED) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
+7
@@ -24,6 +24,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.qmuiteam.qmui.arch.annotation.FragmentScheme;
|
||||
import com.qmuiteam.qmui.arch.annotation.LatestVisitRecord;
|
||||
import com.qmuiteam.qmui.util.QMUIDisplayHelper;
|
||||
import com.qmuiteam.qmui.util.QMUIResHelper;
|
||||
@@ -33,6 +34,7 @@ import com.qmuiteam.qmui.widget.tab.QMUITab;
|
||||
import com.qmuiteam.qmui.widget.tab.QMUITabBuilder;
|
||||
import com.qmuiteam.qmui.widget.tab.QMUITabIndicator;
|
||||
import com.qmuiteam.qmui.widget.tab.QMUITabSegment;
|
||||
import com.qmuiteam.qmuidemo.QDMainActivity;
|
||||
import com.qmuiteam.qmuidemo.R;
|
||||
import com.qmuiteam.qmuidemo.base.BaseFragment;
|
||||
import com.qmuiteam.qmuidemo.lib.Group;
|
||||
@@ -56,6 +58,11 @@ import butterknife.ButterKnife;
|
||||
|
||||
@LatestVisitRecord
|
||||
@Widget(group = Group.Other, name = "固定宽度,内容均分")
|
||||
@FragmentScheme(
|
||||
name = "tab",
|
||||
activities = {QDMainActivity.class},
|
||||
required = {"mode=1"},
|
||||
keysWithIntValue = {"mode"})
|
||||
public class QDTabSegmentFixModeFragment extends BaseFragment {
|
||||
@BindView(R.id.topbar)
|
||||
QMUITopBarLayout mTopBar;
|
||||
|
||||
+3
@@ -19,9 +19,11 @@ package com.qmuiteam.qmuidemo.fragment.components;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import com.qmuiteam.qmui.arch.annotation.FragmentScheme;
|
||||
import com.qmuiteam.qmui.widget.QMUITopBarLayout;
|
||||
import com.qmuiteam.qmui.widget.grouplist.QMUIGroupListView;
|
||||
import com.qmuiteam.qmui.widget.tab.QMUITabSegment;
|
||||
import com.qmuiteam.qmuidemo.QDMainActivity;
|
||||
import com.qmuiteam.qmuidemo.R;
|
||||
import com.qmuiteam.qmuidemo.base.BaseFragment;
|
||||
import com.qmuiteam.qmuidemo.lib.annotation.Widget;
|
||||
@@ -36,6 +38,7 @@ import butterknife.ButterKnife;
|
||||
* @date 2016-10-21
|
||||
*/
|
||||
|
||||
@FragmentScheme(name = "tab", activities = {QDMainActivity.class})
|
||||
@Widget(widgetClass = QMUITabSegment.class, iconRes = R.mipmap.icon_grid_tab_segment)
|
||||
public class QDTabSegmentFragment extends BaseFragment {
|
||||
|
||||
|
||||
+7
@@ -31,6 +31,7 @@ import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.qmuiteam.qmui.arch.annotation.FragmentScheme;
|
||||
import com.qmuiteam.qmui.skin.QMUISkinHelper;
|
||||
import com.qmuiteam.qmui.skin.QMUISkinValueBuilder;
|
||||
import com.qmuiteam.qmui.skin.SkinWriter;
|
||||
@@ -40,6 +41,7 @@ import com.qmuiteam.qmui.widget.tab.QMUITabBuilder;
|
||||
import com.qmuiteam.qmui.widget.tab.QMUITabIndicator;
|
||||
import com.qmuiteam.qmui.widget.tab.QMUITabSegment;
|
||||
import com.qmuiteam.qmui.widget.QMUITopBarLayout;
|
||||
import com.qmuiteam.qmuidemo.QDMainActivity;
|
||||
import com.qmuiteam.qmuidemo.R;
|
||||
import com.qmuiteam.qmuidemo.base.BaseFragment;
|
||||
import com.qmuiteam.qmuidemo.fragment.components.viewpager.QDLazyTestObserver;
|
||||
@@ -55,6 +57,11 @@ import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
@Widget(group = Group.Other, name = "内容自适应,超过父容器则滚动")
|
||||
@FragmentScheme(
|
||||
name = "tab",
|
||||
activities = {QDMainActivity.class},
|
||||
required = {"mode=2"},
|
||||
keysWithIntValue = {"mode"})
|
||||
public class QDTabSegmentScrollableModeFragment extends BaseFragment {
|
||||
@SuppressWarnings("FieldCanBeLocal") private final int TAB_COUNT = 10;
|
||||
|
||||
|
||||
+7
@@ -25,12 +25,14 @@ import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.qmuiteam.qmui.arch.annotation.FragmentScheme;
|
||||
import com.qmuiteam.qmui.util.QMUIDisplayHelper;
|
||||
import com.qmuiteam.qmui.widget.QMUITopBarLayout;
|
||||
import com.qmuiteam.qmui.widget.tab.QMUITab;
|
||||
import com.qmuiteam.qmui.widget.tab.QMUITabBuilder;
|
||||
import com.qmuiteam.qmui.widget.tab.QMUITabIndicator;
|
||||
import com.qmuiteam.qmui.widget.tab.QMUITabSegment;
|
||||
import com.qmuiteam.qmuidemo.QDMainActivity;
|
||||
import com.qmuiteam.qmuidemo.R;
|
||||
import com.qmuiteam.qmuidemo.base.BaseFragment;
|
||||
import com.qmuiteam.qmuidemo.fragment.components.viewpager.QDLazyTestObserver;
|
||||
@@ -56,6 +58,11 @@ import butterknife.ButterKnife;
|
||||
*/
|
||||
|
||||
@Widget(group = Group.Other, name = "内容自适应,添加weight控制间距")
|
||||
@FragmentScheme(
|
||||
name = "tab",
|
||||
activities = {QDMainActivity.class},
|
||||
required = {"mode=3"},
|
||||
keysWithIntValue = {"mode"})
|
||||
public class QDTabSegmentSpaceWeightFragment extends BaseFragment {
|
||||
@SuppressWarnings("FieldCanBeLocal") private final int TAB_COUNT = 3;
|
||||
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmuidemo.fragment.lab;
|
||||
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.widget.EditText;
|
||||
|
||||
import com.qmuiteam.qmui.arch.annotation.LatestVisitRecord;
|
||||
import com.qmuiteam.qmui.widget.QMUITopBarLayout;
|
||||
import com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton;
|
||||
import com.qmuiteam.qmuidemo.R;
|
||||
import com.qmuiteam.qmuidemo.base.BaseFragment;
|
||||
import com.qmuiteam.qmuidemo.lib.Group;
|
||||
import com.qmuiteam.qmuidemo.lib.annotation.Widget;
|
||||
import com.qmuiteam.qmuidemo.manager.QDDataManager;
|
||||
import com.qmuiteam.qmuidemo.manager.QDSchemeManager;
|
||||
|
||||
import butterknife.BindView;
|
||||
import butterknife.ButterKnife;
|
||||
|
||||
@LatestVisitRecord
|
||||
@Widget(group = Group.Lab, name = "Scheme", iconRes = R.mipmap.icon_grid_in_progress)
|
||||
public class QDSchemeFragment extends BaseFragment {
|
||||
|
||||
@BindView(R.id.topbar)
|
||||
QMUITopBarLayout mTopBar;
|
||||
|
||||
@BindView(R.id.edit_text)
|
||||
EditText mEditText;
|
||||
|
||||
@BindView(R.id.button)
|
||||
QMUIRoundButton mBtn;
|
||||
|
||||
@Override
|
||||
protected View onCreateView() {
|
||||
View view = LayoutInflater.from(getContext()).inflate(R.layout.fragment_scheme, null);
|
||||
ButterKnife.bind(this, view);
|
||||
initTopBar();
|
||||
initEditStuff();
|
||||
return view;
|
||||
}
|
||||
|
||||
private void initTopBar() {
|
||||
mTopBar.addLeftBackImageButton().setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
popBackStack();
|
||||
}
|
||||
});
|
||||
|
||||
mTopBar.setTitle(QDDataManager.getInstance().getDescription(this.getClass()).getName());
|
||||
}
|
||||
|
||||
private void initEditStuff() {
|
||||
mBtn.setEnabled(false);
|
||||
mEditText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (s == null || s.length() == 0) {
|
||||
mBtn.setEnabled(false);
|
||||
}
|
||||
mBtn.setEnabled(true);
|
||||
}
|
||||
});
|
||||
mBtn.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
QDSchemeManager.getInstance().handle(mEditText.getText().toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ import com.qmuiteam.qmuidemo.fragment.components.viewpager.QDViewPagerFragment;
|
||||
import com.qmuiteam.qmuidemo.fragment.lab.QDAnimationListViewFragment;
|
||||
import com.qmuiteam.qmuidemo.fragment.lab.QDArchTestFragment;
|
||||
import com.qmuiteam.qmuidemo.fragment.lab.QDContinuousNestedScrollFragment;
|
||||
import com.qmuiteam.qmuidemo.fragment.lab.QDSchemeFragment;
|
||||
import com.qmuiteam.qmuidemo.fragment.lab.QDSnapHelperFragment;
|
||||
import com.qmuiteam.qmuidemo.fragment.lab.QDWebViewFragment;
|
||||
import com.qmuiteam.qmuidemo.fragment.util.QDColorHelperFragment;
|
||||
@@ -144,6 +145,7 @@ public class QDDataManager {
|
||||
mLabNames.add(QDSnapHelperFragment.class);
|
||||
mLabNames.add(QDArchTestFragment.class);
|
||||
mLabNames.add(QDWebViewFragment.class);
|
||||
mLabNames.add(QDSchemeFragment.class);
|
||||
}
|
||||
|
||||
public QDItemDescription getDescription(Class<? extends BaseFragment> cls) {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
*
|
||||
* Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
*
|
||||
* Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
* compliance with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://opensource.org/licenses/MIT
|
||||
*
|
||||
* 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.qmuiteam.qmuidemo.manager;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.qmuiteam.qmui.arch.QMUISwipeBackActivityManager;
|
||||
import com.qmuiteam.qmui.arch.scheme.QMUISchemeHandleInterpolator;
|
||||
import com.qmuiteam.qmui.arch.scheme.QMUISchemeHandler;
|
||||
import com.qmuiteam.qmui.arch.scheme.QMUISchemeParamValueDecoder;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class QDSchemeManager {
|
||||
private static final String TAG = "QDSchemeManager";
|
||||
public static final String SCHEME_PREFIX = "qmui://";
|
||||
private static QDSchemeManager sInstance;
|
||||
|
||||
public static QDSchemeManager getInstance() {
|
||||
if (sInstance == null) {
|
||||
sInstance = new QDSchemeManager();
|
||||
}
|
||||
return sInstance;
|
||||
}
|
||||
|
||||
private QMUISchemeHandler mSchemeHandler;
|
||||
|
||||
private QDSchemeManager() {
|
||||
mSchemeHandler = new QMUISchemeHandler.Builder(SCHEME_PREFIX)
|
||||
.setBlockSameSchemeTimeout(1000)
|
||||
.addInterpolator(new QMUISchemeHandleInterpolator() {
|
||||
@Override
|
||||
public boolean intercept(Activity activity, String action, Map<String, String> params, String origin) {
|
||||
// Log the scheme.
|
||||
Log.i(TAG, "handle scheme: " + origin);
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.addInterpolator(new QMUISchemeParamValueDecoder())
|
||||
.build();
|
||||
}
|
||||
|
||||
public boolean handle(String scheme) {
|
||||
if (!mSchemeHandler.handle(scheme)) {
|
||||
Log.i(TAG, "scheme can not be handled: " + scheme);
|
||||
Toast.makeText(QMUISwipeBackActivityManager.getInstance().getCurrentActivity(),
|
||||
"scheme can not be handled: " + scheme, Toast.LENGTH_SHORT).show();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Tencent is pleased to support the open source community by making QMUI_Android available.
|
||||
|
||||
Copyright (C) 2017-2018 THL A29 Limited, a Tencent company. All rights reserved.
|
||||
|
||||
Licensed under the MIT License (the "License"); you may not use this file except in
|
||||
compliance with the License. You may obtain a copy of the License at
|
||||
|
||||
http://opensource.org/licenses/MIT
|
||||
|
||||
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.
|
||||
-->
|
||||
|
||||
<com.qmuiteam.qmui.widget.QMUIWindowInsetLayout2 xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:background="?attr/app_skin_common_background"
|
||||
app:qmui_skin_background="?attr/app_skin_common_background">
|
||||
|
||||
<com.qmuiteam.qmui.widget.QMUITopBarLayout
|
||||
android:id="@+id/topbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:fitsSystemWindows="true"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="0dp"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintLeft_toLeftOf="parent"
|
||||
app:layout_constraintRight_toRightOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/topbar"
|
||||
android:padding="40dp">
|
||||
|
||||
<TextView
|
||||
style="@style/QDCommonTitle"
|
||||
android:text="请输入 scheme: " />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="20dp"
|
||||
android:background="@drawable/qmui_divider_bottom_bitmap"
|
||||
android:hint="qmui://xxx"
|
||||
android:paddingBottom="6dp"
|
||||
android:singleLine="true"
|
||||
android:textColor="@color/app_color_description"
|
||||
android:textSize="16sp" />
|
||||
|
||||
<com.qmuiteam.qmui.widget.roundwidget.QMUIRoundButton
|
||||
android:id="@+id/button"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_marginTop="20dp"
|
||||
android:gravity="center"
|
||||
android:padding="10dp"
|
||||
android:text="点击跳转"
|
||||
android:textColor="@color/app_color_blue"
|
||||
app:qmui_backgroundColor="@color/app_color_blue_3"
|
||||
app:qmui_borderColor="@color/app_color_blue"
|
||||
app:qmui_borderWidth="1px"
|
||||
app:qmui_skin_background="?attr/app_skin_btn_test_bg_single"
|
||||
app:qmui_skin_border="?attr/app_skin_btn_test_border_single"
|
||||
app:qmui_skin_text_color="?attr/app_skin_btn_test_border_single" />
|
||||
</LinearLayout>
|
||||
</com.qmuiteam.qmui.widget.QMUIWindowInsetLayout2>
|
||||
Reference in New Issue
Block a user