am cfe5778d: am 8f26616d: Merge "LayoutLib: Switch SimpleDateFormat to icu." into mnc-dev

* commit 'cfe5778de871615e8b78bbabb5404dc136774be8':
  LayoutLib: Switch SimpleDateFormat to icu.
This commit is contained in:
Deepanshu Gupta
2015-08-06 23:42:02 +00:00
committed by Android Git Automerger
8 changed files with 227 additions and 14 deletions

View File

@ -1,3 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<component name="InspectionProjectProfileManager">
<profile version="1.0" is_locked="false">
<option name="myName" value="Project Default" />
@ -7,5 +8,6 @@
<option name="CHECK_TRY_CATCH_SECTION" value="true" />
<option name="CHECK_METHOD_BODY" value="true" />
</inspection_tool>
<inspection_tool class="ToArrayCallWithZeroLengthArrayArgument" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

View File

@ -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;
}
}

View File

@ -36,6 +36,7 @@ import android.util.DisplayMetrics;
import android.view.ViewConfiguration_Accessor;
import android.view.inputmethod.InputMethodManager;
import android.view.inputmethod.InputMethodManager_Accessor;
import android.widget.SimpleMonthView_Delegate;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
@ -277,6 +278,7 @@ public abstract class RenderAction<T extends RenderParams> extends FrameworkReso
mContext.getRenderResources().setLogger(null);
}
ParserFactory.setParserFactory(null);
SimpleMonthView_Delegate.clearCache();
}
public static BridgeContext getCurrentContext() {

View File

@ -77,6 +77,8 @@ public class AsmGenerator {
/** Methods to inject. FQCN of class in which method should be injected => runnable that does
* the injection. */
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.
@ -109,20 +111,8 @@ public class AsmGenerator {
// Create the map/set of methods to change to delegates
mDelegateMethods = new HashMap<String, Set<String>>();
for (String signature : createInfo.getDelegateMethods()) {
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);
}
addToMap(createInfo.getDelegateMethods(), mDelegateMethods);
for (String className : createInfo.getDelegateClassNatives()) {
className = binaryToInternalClassName(className);
Set<String> methods = mDelegateMethods.get(className);
@ -187,9 +177,33 @@ public class AsmGenerator {
returnTypes.add(binaryToInternalClassName(className));
}
mPromotedFields = new HashMap<String, Set<String>>();
addToMap(createInfo.getPromotedFields(), mPromotedFields);
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.
* <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);
return cw.toByteArray();
}

View File

@ -119,6 +119,11 @@ public final class CreateInfo implements ICreateInfo {
return excludedClasses;
}
@Override
public String[] getPromotedFields() {
return PROMOTED_FIELDS;
}
@Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return INJECTED_METHODS;
@ -185,6 +190,8 @@ public final class CreateInfo implements ICreateInfo {
"android.view.RenderNode#nSetElevation",
"android.view.RenderNode#nGetElevation",
"android.view.ViewGroup#drawChild",
"android.widget.SimpleMonthView#getTitle",
"android.widget.SimpleMonthView#getDayOfWeekLabel",
"android.widget.TimePickerClockDelegate#getAmOrPmKeyCode",
"com.android.internal.view.menu.MenuBuilder#createNewMenuItem",
"com.android.internal.util.XmlUtils#convertValueToInt",
@ -289,6 +296,12 @@ public final class CreateInfo implements ICreateInfo {
"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.
* The array contains a list of null terminated section starting with the name of the class

View File

@ -77,6 +77,13 @@ public interface ICreateInfo {
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
* called to inject methods into a class.

View File

@ -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);
}
}

View File

@ -137,6 +137,11 @@ public class AsmGeneratorTest {
return new String[0];
}
@Override
public String[] getPromotedFields() {
return new String[0];
}
@Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return new HashMap<String, InjectMethodRunnable>(0);
@ -212,6 +217,11 @@ public class AsmGeneratorTest {
return new String[0];
}
@Override
public String[] getPromotedFields() {
return new String[0];
}
@Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return new HashMap<String, InjectMethodRunnable>(0);
@ -295,6 +305,11 @@ public class AsmGeneratorTest {
return new String[0];
}
@Override
public String[] getPromotedFields() {
return new String[0];
}
@Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return new HashMap<String, InjectMethodRunnable>(0);
@ -373,6 +388,11 @@ public class AsmGeneratorTest {
return new String[0];
}
@Override
public String[] getPromotedFields() {
return new String[0];
}
@Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
HashMap<String, InjectMethodRunnable> map =