下面列出了怎么用android.content.pm.ConfigurationInfo的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* Prefer OpenGL ES 3.0, otherwise 2.0
*
* @param context
* @return
*/
public static int getSupportGLVersion(Context context) {
final ActivityManager activityManager =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
int version = configurationInfo.reqGlEsVersion >= 0x30000 ? 3 : 2;
String glEsVersion = configurationInfo.getGlEsVersion();
Log.d(
TAG,
"reqGlEsVersion: "
+ Integer.toHexString(configurationInfo.reqGlEsVersion)
+ ", glEsVersion: "
+ glEsVersion
+ ", return: "
+ version);
return version;
}
private void checkGLESVersion() {
if (!mGLESVersionCheckComplete) {
// mGLESVersion = SystemProperties.getInt(
// "ro.opengles.version",
// ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo info = am.getDeviceConfigurationInfo();
mGLESVersion = info.reqGlEsVersion;
if (mGLESVersion >= kGLES_20) {
mMultipleGLESContextsAllowed = true;
}
if (LOG_SURFACE) {
Log.w(TAG, "checkGLESVersion mGLESVersion =" + " "
+ mGLESVersion + " mMultipleGLESContextsAllowed = "
+ mMultipleGLESContextsAllowed);
}
mGLESVersionCheckComplete = true;
}
}
/**
* Basic settings for component
*
* @param glSurfaceView - view that will contain the component
* @param backgroundColor - preferable background color for correct colors blending
*/
private void initView(GLSurfaceView glSurfaceView, @ColorInt int backgroundColor) {
// check if the system supports opengl es 2.0.
Context context = glSurfaceView.getContext();
final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
if (supportsEs2) {
// Request an OpenGL ES 2.0 compatible context.
glSurfaceView.setEGLContextClientVersion(2);
// Set the renderer to our demo renderer, defined below.
mRenderer = new BezierRenderer(glSurfaceView, backgroundColor);
glSurfaceView.setRenderer(mRenderer);
glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
} else {
throw new UnsupportedOperationException();
}
}
/**
* Convince feature to add state of multiple system features.
* Uses {@link PackageManager#hasSystemFeature(String)} call.
* <p>
* See https://developer.android.com/guide/topics/manifest/uses-feature-element.html#features-reference for
* available system features.
*
* @param context can be null, but will just return an empty list
* @param labelSystemFeatureMap a map which has ui labels as key and android system feature string
* (as returned as name by {@link PackageManager#getSystemAvailableFeatures()}) as value
* @return list of page-entries (one for each map entry)
*/
public static List<PageEntry<?>> createSystemFeatureInfo(@Nullable Context context, Map<CharSequence, String> labelSystemFeatureMap) {
List<PageEntry<?>> entries = new ArrayList<>();
if (context != null) {
for (Map.Entry<CharSequence, String> entry : labelSystemFeatureMap.entrySet()) {
boolean supported;
if (entry.getValue().matches("^-?\\d+$")) {
final ConfigurationInfo configurationInfo = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE)).getDeviceConfigurationInfo();
supported = configurationInfo.reqGlEsVersion >= Integer.valueOf(entry.getValue());
} else {
supported = context.getPackageManager().hasSystemFeature(entry.getValue());
}
entries.add(Hood.get().createPropertyEntry(entry.getKey(), String.valueOf(supported)));
}
}
return entries;
}
private void initGlSurfaceView() {
mGLSurfaceView = new StarWarsTilesGLSurfaceView(getContext());
mGLSurfaceView.setBackgroundColor(Color.TRANSPARENT);
// Check if the system supports OpenGL ES 2.0.
final ActivityManager activityManager = (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
if (supportsEs2) {
// Request an OpenGL ES 2.0 compatible context.
mGLSurfaceView.setEGLContextClientVersion(2);
mRenderer = new StarWarsRenderer(mGLSurfaceView, this, mAnimationDuration, mNumberOfTilesX);
mGLSurfaceView.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
mGLSurfaceView.getHolder().setFormat(PixelFormat.TRANSPARENT);
mGLSurfaceView.setRenderer(mRenderer);
mGLSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
mGLSurfaceView.setZOrderOnTop(true);
} else {
throw new UnsupportedOperationException();
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// Turn off the window's title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
mGLSurfaceView = new GLSurfaceView(this);
// Check if the system supports OpenGL ES 2.0.
final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
if (supportsEs2)
{
// Request an OpenGL ES 2.0 compatible context.
mGLSurfaceView.setEGLContextClientVersion(2);
// Set the renderer to our demo renderer, defined below.
mGLSurfaceView.setRenderer(new LessonOneRenderer());
}
else
{
// This is where you could create an OpenGL ES 1.x compatible
// renderer if you wanted to support both ES 1 and ES 2.
return;
}
setContentView(mGLSurfaceView);
}
public static IGLVersion getGLVersion(Context context)
{
IGLVersion glVersion = XeGLUnknown.GL_UNKNOWN;
final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
String glesVersionString = configurationInfo.getGlEsVersion();
// This is messy...
if (XeGLES2.GLES2_0.versionString.equals(glesVersionString))
{
glVersion = XeGLES2.GLES2_0;
}
else if (XeGLES3.GLES3_0.versionString.equals(glesVersionString))
{
glVersion = XeGLES3.GLES3_0;
}
else if (XeGLES3.GLES3_1.versionString.equals(glesVersionString))
{
glVersion = XeGLES3.GLES3_1;
}
return glVersion;
}
/**
* Check whether Google Maps v2 is supported on this device.
*/
public static boolean isGoogleMapsV2Supported(final Context aContext) {
try {
// first check if Google Play Services is available
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(aContext);
if (resultCode == ConnectionResult.SUCCESS) {
// then check if OpenGL ES 2.0 is available
final ActivityManager activityManager =
(ActivityManager) aContext.getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
return configurationInfo.reqGlEsVersion >= 0x20000;
}
} catch (Throwable e) {
}
return false;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final Context context = getActivity();
final View v = inflater.inflate(getContentViewId(), container, false);
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo info = am.getDeviceConfigurationInfo();
if (info.reqGlEsVersion < 0x20000)
throw new Error("OpenGL ES 2.0 is not supported by this device");
loading = v.findViewById(R.id.loading);
gLView = (GLSurfaceView) v.findViewById(R.id.gl);
renderer = new ModelRenderer(context);
renderer.setSurfaceView(gLView);
gLView.setRenderer(renderer);
loader.loadModel(getActivity(), this);
return v;
}
/**
* Get the device configuration attributes.
*/
public ConfigurationInfo getDeviceConfigurationInfo() {
try {
return getService().getDeviceConfigurationInfo();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
* Get the device configuration attributes.
*/
public ConfigurationInfo getDeviceConfigurationInfo() {
try {
return getService().getDeviceConfigurationInfo();
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
private void createGLSurfaceView() {
if (glSurfaceView != null) {
glSurfaceView.onDestroy();
glSurfaceView = null;
}
glSurfaceView = new GLWallpaperSurfaceView(context);
final ActivityManager activityManager = (ActivityManager)getSystemService(
Context.ACTIVITY_SERVICE
);
if (activityManager == null) {
throw new RuntimeException("Cannot get ActivityManager");
}
final ConfigurationInfo configInfo = activityManager.getDeviceConfigurationInfo();
if (configInfo.reqGlEsVersion >= 0x30000) {
Utils.debug(TAG, "Support GLESv3");
glSurfaceView.setEGLContextClientVersion(3);
renderer = new GLES30WallpaperRenderer(context);
} else if (configInfo.reqGlEsVersion >= 0x20000) {
Utils.debug(TAG, "Fallback to GLESv2");
glSurfaceView.setEGLContextClientVersion(2);
renderer = new GLES20WallpaperRenderer(context);
} else {
Toast.makeText(context, R.string.gles_version, Toast.LENGTH_LONG).show();
throw new RuntimeException("Needs GLESv2 or higher");
}
glSurfaceView.setPreserveEGLContextOnPause(true);
glSurfaceView.setRenderer(renderer);
// On demand render will lead to black screen.
glSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
}
/**
* Checks if OpenGL ES 2.0 is supported on the current device.
*
* @param context the context
* @return true, if successful
*/
private boolean supportsOpenGLES2(final Context context) {
final ActivityManager activityManager = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo =
activityManager.getDeviceConfigurationInfo();
return configurationInfo.reqGlEsVersion >= 0x20000;
}
public static int getSupportGLVersion(Context context) {
final ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
int version = configurationInfo.reqGlEsVersion >= 0x30000 ? 3 : 2;
String glEsVersion = configurationInfo.getGlEsVersion();
Log.e(TAG, "reqGlEsVersion: " + Integer.toHexString(configurationInfo.reqGlEsVersion) + ", glEsVersion:" + glEsVersion);
return version;
}
public static boolean IsSupported(Context context) {
ActivityManager am =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo info = am.getDeviceConfigurationInfo();
if(info.reqGlEsVersion >= 0x20000) {
// Open GL ES 2.0 is supported.
return true;
}
return false;
}
/**
* Checks if OpenGL ES 2.0 is supported on the current device.
*
* @param context the context
* @return true, if successful
*/
private boolean supportsOpenGLES2(final Context context) {
final ActivityManager activityManager = (ActivityManager)
context.getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo =
activityManager.getDeviceConfigurationInfo();
return configurationInfo.reqGlEsVersion >= 0x20000;
}
private void checkGLESVersion() {
if (!mGLESVersionCheckComplete) {
mGLESVersion = SystemProperties.getInt(
"ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
if (mGLESVersion >= kGLES_20) {
mMultipleGLESContextsAllowed = true;
}
if (LOG_SURFACE) {
Log.w(TAG, "checkGLESVersion mGLESVersion =" +
" " + mGLESVersion + " mMultipleGLESContextsAllowed = " + mMultipleGLESContextsAllowed);
}
mGLESVersionCheckComplete = true;
}
}
private void checkGLESVersion() {
if (!mGLESVersionCheckComplete) {
mGLESVersion = SystemProperties.getInt("ro.opengles.version", ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
if (mGLESVersion >= kGLES_20) {
mMultipleGLESContextsAllowed = true;
}
if (LOG_SURFACE) {
Log.w(TAG, "checkGLESVersion mGLESVersion =" +
" " + mGLESVersion + " mMultipleGLESContextsAllowed = " + mMultipleGLESContextsAllowed);
}
mGLESVersionCheckComplete = true;
}
}
public static boolean IsSupported(Context context) {
LogS.d(TAG, " IsSupported()");
ActivityManager am = (ActivityManager) context
.getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo info = am.getDeviceConfigurationInfo();
if (info.reqGlEsVersion >= 0x20000) {
// Open GL ES 2.0 is supported.
return true;
}
return false;
}
public static boolean IsSupported(Context context) {
ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo info = am.getDeviceConfigurationInfo();
if (info.reqGlEsVersion >= 0x20000) {
Log.w(TAG, "IsSupported true");
// Open GL ES 2.0 is supported.
return true;
}
Log.w(TAG, "IsSupported false");
return false;
}
public static String getGLVersion () {
if (ClientProperties.getApplicationContext() != null) {
final ActivityManager activityManager = (ActivityManager)ClientProperties.getApplicationContext().getSystemService(Context.ACTIVITY_SERVICE);
if (activityManager != null) {
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
if (configurationInfo != null) {
return configurationInfo.getGlEsVersion();
}
}
}
return null;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_demo);
ButterKnife.bind(this);
// Check if the system supports OpenGL ES 2.0.
final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
if (supportsEs2) {
// Request an OpenGL ES 2.0 compatible context.
mGlSurfaceView.setEGLContextClientVersion(2);
// Set the renderer to our demo renderer, defined below.
ParticleSystemRenderer mRenderer = new ParticleSystemRenderer(mGlSurfaceView);
mGlSurfaceView.setRenderer(mRenderer);
mGlSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
} else {
throw new UnsupportedOperationException();
}
if (savedInstanceState == null) {
showGreetings();
}
}
/**
* Boring view inflation / creation
*/
private View getConfigurationView(ViewGroup viewGroup, View convertView, int index) {
ViewHolder viewHolder;
if (!checkIfConvertViewMatch(convertView, CONFIGURATION)) {
convertView = mLayoutInflater.inflate(R.layout.detail_features, viewGroup);
viewHolder = new ViewHolder();
viewHolder.currentViewType = CONFIGURATION;
viewHolder.textView1 = (TextView) convertView.findViewById(R.id.name);
viewHolder.textView2 = (TextView) convertView.findViewById(R.id.flags);
convertView.findViewById(R.id.gles_ver).setVisibility(View.GONE);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
final ConfigurationInfo configurationInfo = mPackageInfo.configPreferences[index];
convertView.setBackgroundColor(index % 2 == 0 ? mColorGrey1 : mColorGrey2);
//GLES ver
viewHolder.textView1.setText(getString(R.string.gles_ver) + ": " + configurationInfo.reqGlEsVersion);
//Falg
viewHolder.textView2.setText(getString(R.string.input_features) + ": " +
Utils.getInputFeaturesString(configurationInfo.reqInputFeatures));
return convertView;
}
public static String getInputFeaturesString(int flag) {
String string = "";
if ((flag & ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV) != 0)
string += "Five way nav";
if ((flag & ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD) != 0)
string += (string.length() == 0 ? "" : "|") + "Hard keyboard";
return string.length() == 0 ? "null" : string;
}
private static void checkGLES20Support(final Context pContext) throws DeviceNotSupportedException {
final ActivityManager activityManager = (ActivityManager) pContext.getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
if (configurationInfo.reqGlEsVersion < 0x20000) {
throw new DeviceNotSupportedException(DeviceNotSupportedCause.GLES2_UNSUPPORTED);
}
}
private boolean detectOpenGLES30()
{
ActivityManager am =
( ActivityManager ) getSystemService ( Context.ACTIVITY_SERVICE );
ConfigurationInfo info = am.getDeviceConfigurationInfo();
return ( info.reqGlEsVersion >= 0x30000 );
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// Turn off the window's title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
mGLSurfaceView = new GLSurfaceView(this);
// Check if the system supports OpenGL ES 2.0.
final ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000;
if (supportsEs2)
{
// Request an OpenGL ES 2.0 compatible context.
mGLSurfaceView.setEGLContextClientVersion(2);
// Set the renderer to our demo renderer, defined below.
mGLSurfaceView.setRenderer(new LessonOneRenderer());
}
else
{
// This is where you could create an OpenGL ES 1.x compatible
// renderer if you wanted to support both ES 1 and ES 2.
return;
}
setContentView(mGLSurfaceView);
}
private void init() {
if (isInEditMode()) {
return;
}
mCameraView = new CameraView(getContext());
addView(mCameraView, LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
final ActivityManager activityManager = (ActivityManager) getContext()
.getSystemService(Context.ACTIVITY_SERVICE);
final ConfigurationInfo config = activityManager
.getDeviceConfigurationInfo();
if (config.reqGlEsVersion >= 0x20000 || Build.PRODUCT.startsWith("sdk")) {
// Add ARSurfaceView only if OpenGL ES Version 2 supported
mARSurfaceView = new ARSurfaceView(this);
mARSurfaceView.setKeepScreenOn(true);
mARSurfaceView.setZOrderMediaOverlay(true);
addView(mARSurfaceView, new FrameLayout.LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
mCanvasOverlayView = new ARCanvasSurfaceView(this);
addView(mCanvasOverlayView, LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
}
public static boolean IsSupported(Context context) {
ActivityManager am =
(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
ConfigurationInfo info = am.getDeviceConfigurationInfo();
if(info.reqGlEsVersion >= 0x20000) {
// Open GL ES 2.0 is supported.
return true;
}
return false;
}
private void writeDeviceConfig(ProtoOutputStream protoOutputStream, long fieldId,
PrintWriter pw, Configuration config, DisplayManager dm) {
Point stableSize = dm.getStableDisplaySize();
long token = -1;
if (protoOutputStream != null) {
token = protoOutputStream.start(fieldId);
protoOutputStream.write(DeviceConfigurationProto.STABLE_SCREEN_WIDTH_PX, stableSize.x);
protoOutputStream.write(DeviceConfigurationProto.STABLE_SCREEN_HEIGHT_PX, stableSize.y);
protoOutputStream.write(DeviceConfigurationProto.STABLE_DENSITY_DPI,
DisplayMetrics.DENSITY_DEVICE_STABLE);
}
if (pw != null) {
pw.print("stable-width-px: "); pw.println(stableSize.x);
pw.print("stable-height-px: "); pw.println(stableSize.y);
pw.print("stable-density-dpi: "); pw.println(DisplayMetrics.DENSITY_DEVICE_STABLE);
}
MemInfoReader memreader = new MemInfoReader();
memreader.readMemInfo();
KeyguardManager kgm = mInternal.mContext.getSystemService(KeyguardManager.class);
if (protoOutputStream != null) {
protoOutputStream.write(DeviceConfigurationProto.TOTAL_RAM, memreader.getTotalSize());
protoOutputStream.write(DeviceConfigurationProto.LOW_RAM,
ActivityManager.isLowRamDeviceStatic());
protoOutputStream.write(DeviceConfigurationProto.MAX_CORES,
Runtime.getRuntime().availableProcessors());
protoOutputStream.write(DeviceConfigurationProto.HAS_SECURE_SCREEN_LOCK,
kgm.isDeviceSecure());
}
if (pw != null) {
pw.print("total-ram: "); pw.println(memreader.getTotalSize());
pw.print("low-ram: "); pw.println(ActivityManager.isLowRamDeviceStatic());
pw.print("max-cores: "); pw.println(Runtime.getRuntime().availableProcessors());
pw.print("has-secure-screen-lock: "); pw.println(kgm.isDeviceSecure());
}
ConfigurationInfo configInfo = mInternal.getDeviceConfigurationInfo();
if (configInfo.reqGlEsVersion != ConfigurationInfo.GL_ES_VERSION_UNDEFINED) {
if (protoOutputStream != null) {
protoOutputStream.write(DeviceConfigurationProto.OPENGL_VERSION,
configInfo.reqGlEsVersion);
}
if (pw != null) {
pw.print("opengl-version: 0x");
pw.println(Integer.toHexString(configInfo.reqGlEsVersion));
}
}
Set<String> glExtensionsSet = getGlExtensionsFromDriver();
String[] glExtensions = new String[glExtensionsSet.size()];
glExtensions = glExtensionsSet.toArray(glExtensions);
Arrays.sort(glExtensions);
for (int i = 0; i < glExtensions.length; i++) {
if (protoOutputStream != null) {
protoOutputStream.write(DeviceConfigurationProto.OPENGL_EXTENSIONS,
glExtensions[i]);
}
if (pw != null) {
pw.print("opengl-extensions: "); pw.println(glExtensions[i]);
}
}
PackageManager pm = mInternal.mContext.getPackageManager();
List<SharedLibraryInfo> slibs = pm.getSharedLibraries(0);
Collections.sort(slibs, Comparator.comparing(SharedLibraryInfo::getName));
for (int i = 0; i < slibs.size(); i++) {
if (protoOutputStream != null) {
protoOutputStream.write(DeviceConfigurationProto.SHARED_LIBRARIES,
slibs.get(i).getName());
}
if (pw != null) {
pw.print("shared-libraries: "); pw.println(slibs.get(i).getName());
}
}
FeatureInfo[] features = pm.getSystemAvailableFeatures();
Arrays.sort(features, (o1, o2) ->
(o1.name == o2.name ? 0 : (o1.name == null ? -1 : o1.name.compareTo(o2.name))));
for (int i = 0; i < features.length; i++) {
if (features[i].name != null) {
if (protoOutputStream != null) {
protoOutputStream.write(DeviceConfigurationProto.FEATURES, features[i].name);
}
if (pw != null) {
pw.print("features: "); pw.println(features[i].name);
}
}
}
if (protoOutputStream != null) {
protoOutputStream.end(token);
}
}