am 8f26616d
: Merge "LayoutLib: Switch SimpleDateFormat to icu." into mnc-dev
* commit '8f26616d1a1765267d6a3ba09e7ac1bd6edeca67': LayoutLib: Switch SimpleDateFormat to icu.
This commit is contained in:
@ -1,3 +1,4 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<component name="InspectionProjectProfileManager">
|
<component name="InspectionProjectProfileManager">
|
||||||
<profile version="1.0" is_locked="false">
|
<profile version="1.0" is_locked="false">
|
||||||
<option name="myName" value="Project Default" />
|
<option name="myName" value="Project Default" />
|
||||||
@ -7,5 +8,6 @@
|
|||||||
<option name="CHECK_TRY_CATCH_SECTION" value="true" />
|
<option name="CHECK_TRY_CATCH_SECTION" value="true" />
|
||||||
<option name="CHECK_METHOD_BODY" value="true" />
|
<option name="CHECK_METHOD_BODY" value="true" />
|
||||||
</inspection_tool>
|
</inspection_tool>
|
||||||
|
<inspection_tool class="ToArrayCallWithZeroLengthArrayArgument" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
</profile>
|
</profile>
|
||||||
</component>
|
</component>
|
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package android.widget;
|
||||||
|
|
||||||
|
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
import android.icu.text.SimpleDateFormat;
|
||||||
|
import android.text.format.DateFormat;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delegate that provides implementation for some methods in {@link SimpleMonthView}.
|
||||||
|
* <p/>
|
||||||
|
* Through the layoutlib_create tool, selected methods of SimpleMonthView have been replaced by
|
||||||
|
* calls to methods of the same name in this delegate class.
|
||||||
|
* <p/>
|
||||||
|
* The main purpose of this class is to use {@link android.icu.text.SimpleDateFormat} instead of
|
||||||
|
* {@link java.text.SimpleDateFormat}.
|
||||||
|
*/
|
||||||
|
public class SimpleMonthView_Delegate {
|
||||||
|
|
||||||
|
private static final String DEFAULT_TITLE_FORMAT = "MMMMy";
|
||||||
|
private static final String DAY_OF_WEEK_FORMAT = "EEEEE";
|
||||||
|
|
||||||
|
// Maintain a cache of the last view used, so that the formatters can be reused.
|
||||||
|
@Nullable private static SimpleMonthView sLastView;
|
||||||
|
@Nullable private static SimpleMonthView_Delegate sLastDelegate;
|
||||||
|
|
||||||
|
private SimpleDateFormat mTitleFormatter;
|
||||||
|
private SimpleDateFormat mDayOfWeekFormatter;
|
||||||
|
|
||||||
|
private Locale locale;
|
||||||
|
|
||||||
|
@LayoutlibDelegate
|
||||||
|
/*package*/ static CharSequence getTitle(SimpleMonthView view) {
|
||||||
|
if (view.mTitle == null) {
|
||||||
|
SimpleMonthView_Delegate delegate = getDelegate(view);
|
||||||
|
if (delegate.mTitleFormatter == null) {
|
||||||
|
delegate.mTitleFormatter = new SimpleDateFormat(DateFormat.getBestDateTimePattern(
|
||||||
|
getLocale(delegate, view), DEFAULT_TITLE_FORMAT));
|
||||||
|
}
|
||||||
|
view.mTitle = delegate.mTitleFormatter.format(view.mCalendar.getTime());
|
||||||
|
}
|
||||||
|
return view.mTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
@LayoutlibDelegate
|
||||||
|
/*package*/ static String getDayOfWeekLabel(SimpleMonthView view, int dayOfWeek) {
|
||||||
|
view.mDayOfWeekLabelCalendar.set(Calendar.DAY_OF_WEEK, dayOfWeek);
|
||||||
|
SimpleMonthView_Delegate delegate = getDelegate(view);
|
||||||
|
if (delegate.mDayOfWeekFormatter == null) {
|
||||||
|
delegate.mDayOfWeekFormatter =
|
||||||
|
new SimpleDateFormat(DAY_OF_WEEK_FORMAT, getLocale(delegate, view));
|
||||||
|
}
|
||||||
|
return delegate.mDayOfWeekFormatter.format(view.mDayOfWeekLabelCalendar.getTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Locale getLocale(SimpleMonthView_Delegate delegate, SimpleMonthView view) {
|
||||||
|
if (delegate.locale == null) {
|
||||||
|
delegate.locale = view.getContext().getResources().getConfiguration().locale;
|
||||||
|
}
|
||||||
|
return delegate.locale;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
private static SimpleMonthView_Delegate getDelegate(SimpleMonthView view) {
|
||||||
|
if (view == sLastView) {
|
||||||
|
assert sLastDelegate != null;
|
||||||
|
return sLastDelegate;
|
||||||
|
} else {
|
||||||
|
sLastView = view;
|
||||||
|
sLastDelegate = new SimpleMonthView_Delegate();
|
||||||
|
return sLastDelegate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearCache() {
|
||||||
|
sLastView = null;
|
||||||
|
sLastDelegate = null;
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,7 @@ import android.util.DisplayMetrics;
|
|||||||
import android.view.ViewConfiguration_Accessor;
|
import android.view.ViewConfiguration_Accessor;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
import android.view.inputmethod.InputMethodManager_Accessor;
|
import android.view.inputmethod.InputMethodManager_Accessor;
|
||||||
|
import android.widget.SimpleMonthView_Delegate;
|
||||||
|
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -277,6 +278,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
|
|||||||
mContext.getRenderResources().setLogger(null);
|
mContext.getRenderResources().setLogger(null);
|
||||||
}
|
}
|
||||||
ParserFactory.setParserFactory(null);
|
ParserFactory.setParserFactory(null);
|
||||||
|
SimpleMonthView_Delegate.clearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static BridgeContext getCurrentContext() {
|
public static BridgeContext getCurrentContext() {
|
||||||
|
@ -77,6 +77,8 @@ public class AsmGenerator {
|
|||||||
/** Methods to inject. FQCN of class in which method should be injected => runnable that does
|
/** Methods to inject. FQCN of class in which method should be injected => runnable that does
|
||||||
* the injection. */
|
* the injection. */
|
||||||
private final Map<String, ICreateInfo.InjectMethodRunnable> mInjectedMethodsMap;
|
private final Map<String, ICreateInfo.InjectMethodRunnable> mInjectedMethodsMap;
|
||||||
|
/** A map { FQCN => set { field names } } which should be promoted to public visibility */
|
||||||
|
private final Map<String, Set<String>> mPromotedFields;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new generator that can generate the output JAR with the stubbed classes.
|
* Creates a new generator that can generate the output JAR with the stubbed classes.
|
||||||
@ -109,20 +111,8 @@ public class AsmGenerator {
|
|||||||
|
|
||||||
// Create the map/set of methods to change to delegates
|
// Create the map/set of methods to change to delegates
|
||||||
mDelegateMethods = new HashMap<String, Set<String>>();
|
mDelegateMethods = new HashMap<String, Set<String>>();
|
||||||
for (String signature : createInfo.getDelegateMethods()) {
|
addToMap(createInfo.getDelegateMethods(), mDelegateMethods);
|
||||||
int pos = signature.indexOf('#');
|
|
||||||
if (pos <= 0 || pos >= signature.length() - 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String className = binaryToInternalClassName(signature.substring(0, pos));
|
|
||||||
String methodName = signature.substring(pos + 1);
|
|
||||||
Set<String> methods = mDelegateMethods.get(className);
|
|
||||||
if (methods == null) {
|
|
||||||
methods = new HashSet<String>();
|
|
||||||
mDelegateMethods.put(className, methods);
|
|
||||||
}
|
|
||||||
methods.add(methodName);
|
|
||||||
}
|
|
||||||
for (String className : createInfo.getDelegateClassNatives()) {
|
for (String className : createInfo.getDelegateClassNatives()) {
|
||||||
className = binaryToInternalClassName(className);
|
className = binaryToInternalClassName(className);
|
||||||
Set<String> methods = mDelegateMethods.get(className);
|
Set<String> methods = mDelegateMethods.get(className);
|
||||||
@ -187,9 +177,33 @@ public class AsmGenerator {
|
|||||||
returnTypes.add(binaryToInternalClassName(className));
|
returnTypes.add(binaryToInternalClassName(className));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mPromotedFields = new HashMap<String, Set<String>>();
|
||||||
|
addToMap(createInfo.getPromotedFields(), mPromotedFields);
|
||||||
|
|
||||||
mInjectedMethodsMap = createInfo.getInjectedMethodsMap();
|
mInjectedMethodsMap = createInfo.getInjectedMethodsMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For each value in the array, split the value on '#' and add the parts to the map as key
|
||||||
|
* and value.
|
||||||
|
*/
|
||||||
|
private void addToMap(String[] entries, Map<String, Set<String>> map) {
|
||||||
|
for (String entry : entries) {
|
||||||
|
int pos = entry.indexOf('#');
|
||||||
|
if (pos <= 0 || pos >= entry.length() - 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String className = binaryToInternalClassName(entry.substring(0, pos));
|
||||||
|
String methodOrFieldName = entry.substring(pos + 1);
|
||||||
|
Set<String> set = map.get(className);
|
||||||
|
if (set == null) {
|
||||||
|
set = new HashSet<String>();
|
||||||
|
map.put(className, set);
|
||||||
|
}
|
||||||
|
set.add(methodOrFieldName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the list of classes that have not been renamed yet.
|
* Returns the list of classes that have not been renamed yet.
|
||||||
* <p/>
|
* <p/>
|
||||||
@ -380,6 +394,10 @@ public class AsmGenerator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Set<String> promoteFields = mPromotedFields.get(className);
|
||||||
|
if (promoteFields != null && !promoteFields.isEmpty()) {
|
||||||
|
cv = new PromoteFieldClassAdapter(cv, promoteFields);
|
||||||
|
}
|
||||||
cr.accept(cv, 0);
|
cr.accept(cv, 0);
|
||||||
return cw.toByteArray();
|
return cw.toByteArray();
|
||||||
}
|
}
|
||||||
|
@ -119,6 +119,11 @@ public final class CreateInfo implements ICreateInfo {
|
|||||||
return excludedClasses;
|
return excludedClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getPromotedFields() {
|
||||||
|
return PROMOTED_FIELDS;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
|
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
|
||||||
return INJECTED_METHODS;
|
return INJECTED_METHODS;
|
||||||
@ -185,6 +190,8 @@ public final class CreateInfo implements ICreateInfo {
|
|||||||
"android.view.RenderNode#nSetElevation",
|
"android.view.RenderNode#nSetElevation",
|
||||||
"android.view.RenderNode#nGetElevation",
|
"android.view.RenderNode#nGetElevation",
|
||||||
"android.view.ViewGroup#drawChild",
|
"android.view.ViewGroup#drawChild",
|
||||||
|
"android.widget.SimpleMonthView#getTitle",
|
||||||
|
"android.widget.SimpleMonthView#getDayOfWeekLabel",
|
||||||
"android.widget.TimePickerClockDelegate#getAmOrPmKeyCode",
|
"android.widget.TimePickerClockDelegate#getAmOrPmKeyCode",
|
||||||
"com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
|
"com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
|
||||||
"com.android.internal.util.XmlUtils#convertValueToInt",
|
"com.android.internal.util.XmlUtils#convertValueToInt",
|
||||||
@ -289,6 +296,12 @@ public final class CreateInfo implements ICreateInfo {
|
|||||||
"org.kxml2.io.KXmlParser"
|
"org.kxml2.io.KXmlParser"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private final static String[] PROMOTED_FIELDS = new String[] {
|
||||||
|
"android.widget.SimpleMonthView#mTitle",
|
||||||
|
"android.widget.SimpleMonthView#mCalendar",
|
||||||
|
"android.widget.SimpleMonthView#mDayOfWeekLabelCalendar"
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of classes for which the methods returning them should be deleted.
|
* List of classes for which the methods returning them should be deleted.
|
||||||
* The array contains a list of null terminated section starting with the name of the class
|
* The array contains a list of null terminated section starting with the name of the class
|
||||||
|
@ -77,6 +77,13 @@ public interface ICreateInfo {
|
|||||||
|
|
||||||
Set<String> getExcludedClasses();
|
Set<String> getExcludedClasses();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a list of fields which should be promoted to public visibility. The array values
|
||||||
|
* are in the form of the binary FQCN of the class containing the field and the field name
|
||||||
|
* separated by a '#'.
|
||||||
|
*/
|
||||||
|
String[] getPromotedFields();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a map from binary FQCN className to {@link InjectMethodRunnable} which will be
|
* Returns a map from binary FQCN className to {@link InjectMethodRunnable} which will be
|
||||||
* called to inject methods into a class.
|
* called to inject methods into a class.
|
||||||
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.android.tools.layoutlib.create;
|
||||||
|
|
||||||
|
import org.objectweb.asm.ClassVisitor;
|
||||||
|
import org.objectweb.asm.FieldVisitor;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
|
||||||
|
import static org.objectweb.asm.Opcodes.ACC_PROTECTED;
|
||||||
|
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
|
||||||
|
import static org.objectweb.asm.Opcodes.ASM4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Promotes given fields to public visibility.
|
||||||
|
*/
|
||||||
|
public class PromoteFieldClassAdapter extends ClassVisitor {
|
||||||
|
|
||||||
|
private final Set<String> mFieldNames;
|
||||||
|
private static final int ACC_NOT_PUBLIC = ~(ACC_PRIVATE | ACC_PROTECTED);
|
||||||
|
|
||||||
|
public PromoteFieldClassAdapter(ClassVisitor cv, Set<String> fieldNames) {
|
||||||
|
super(ASM4, cv);
|
||||||
|
mFieldNames = fieldNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FieldVisitor visitField(int access, String name, String desc, String signature,
|
||||||
|
Object value) {
|
||||||
|
if (mFieldNames.contains(name)) {
|
||||||
|
if ((access & ACC_PUBLIC) == 0) {
|
||||||
|
access = (access & ACC_NOT_PUBLIC) | ACC_PUBLIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.visitField(access, name, desc, signature, value);
|
||||||
|
}
|
||||||
|
}
|
@ -137,6 +137,11 @@ public class AsmGeneratorTest {
|
|||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getPromotedFields() {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
|
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
|
||||||
return new HashMap<String, InjectMethodRunnable>(0);
|
return new HashMap<String, InjectMethodRunnable>(0);
|
||||||
@ -212,6 +217,11 @@ public class AsmGeneratorTest {
|
|||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getPromotedFields() {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
|
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
|
||||||
return new HashMap<String, InjectMethodRunnable>(0);
|
return new HashMap<String, InjectMethodRunnable>(0);
|
||||||
@ -295,6 +305,11 @@ public class AsmGeneratorTest {
|
|||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getPromotedFields() {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
|
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
|
||||||
return new HashMap<String, InjectMethodRunnable>(0);
|
return new HashMap<String, InjectMethodRunnable>(0);
|
||||||
@ -373,6 +388,11 @@ public class AsmGeneratorTest {
|
|||||||
return new String[0];
|
return new String[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getPromotedFields() {
|
||||||
|
return new String[0];
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
|
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
|
||||||
HashMap<String, InjectMethodRunnable> map =
|
HashMap<String, InjectMethodRunnable> map =
|
||||||
|
Reference in New Issue
Block a user