如何指定只对手机或平板电脑在Android活动只对、平板、电脑、手机

2023-09-12 22:13:05 作者:换我心为你心

我正在审查谷歌I / O 2012届应用和碰到这个TODO

I was reviewing the Google I/O Session 2012 app and came across this TODO

// TODO: use <meta-data> element instead
private static final Class[] sPhoneActivities = new Class[]{
        MapActivity.class,
        SessionDetailActivity.class,
        SessionsActivity.class,
        TrackDetailActivity.class,
        VendorDetailActivity.class,
};

// TODO: use <meta-data> element instead
private static final Class[] sTabletActivities = new Class[]{
        MapMultiPaneActivity.class,
        SessionsVendorsMultiPaneActivity.class,
};

public static void enableDisableActivities(final Context context) {
    boolean isHoneycombTablet = isHoneycombTablet(context);
    PackageManager pm = context.getPackageManager();

    // Enable/disable phone activities
    for (Class a : sPhoneActivities) {
        pm.setComponentEnabledSetting(new ComponentName(context, a),
                isHoneycombTablet
                        ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED
                        : PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);
    }

    // Enable/disable tablet activities
    for (Class a : sTabletActivities) {
        pm.setComponentEnabledSetting(new ComponentName(context, a),
                isHoneycombTablet
                        ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);
    }
}

这让我不知道如何将一个执行该TODO。

Which made me wonder how would one execute that TODO.

推荐答案

我想出了这个办法(注:这是的谷歌I / O会议2012应用 UIUtilis.java):

I came up with this approach (Note: this is modelled after the Google I/O Session 2012 app UIUtilis.java):

的Andr​​oidManifest.xml 定义活动 s到包括&LT;荟萃数据&GT;

<!-- Note: specify the target device for Activities with target_device meta-data of "universal|phone|tablet"
           see UIUtils.java (configureDeviceSpecificActivities) for more details. -->

<!-- Activities for both phones and tablets -->
<activity android:name=".ui.AccountActivity" 
          android:configChanges="orientation|keyboardHidden" 
          android:label="@string/app_name"
          android:theme="@style/Theme.Accounts">
          <meta-data android:name="target_device" android:value="universal"/>
</activity>

<!-- Activities for tablets -->
<activity android:name=".ui.CoolMultipaneActivity"
          android:label="@string/app_name">
          <meta-data android:name="target_device" android:value="tablet"/>

艰苦的工作被放在方法 configureDeviceSpecificActivities(上下文的背景下)

/**
 * Enables and disables {@linkplain android.app.Activity activities} based on their "target_device" meta-data and
 * the current device. Add <meta-data name="target_device" value="tablet|phone|universal" /> to an activity to
 * specify its target device.
 * @param context the current context of the device
 * @see #isHoneycombTablet(android.content.Context)
 */
public static void configureDeviceSpecificActivities(Context context) {
    final PackageManager package_manager = context.getPackageManager();
    final boolean is_honeycomb_tablet = isHoneycombTablet(context);
    try {
        final ActivityInfo[] activity_info = package_manager.getPackageInfo(context.getPackageName(),
                PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA).activities;
        for (ActivityInfo info : activity_info) {
            final String target_device = info.metaData.getString("target_device");
            if (target_device == null) break;
            target_device = target_device.toLowerCase(Locale.US);
            final boolean is_for_tablet = target_device.equals("tablet");
            final boolean is_for_phone = target_device.equals("phone");
            final String class_name = info.name;
            package_manager.setComponentEnabledSetting(new ComponentName(context, Class.forName(class_name)),
                    is_honeycomb_tablet && is_for_phone
                            ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED
                            : !is_honeycomb_tablet && is_for_tablet
                            ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED
                            : PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                    PackageManager.DONT_KILL_APP);
        }
    } catch (PackageManager.NameNotFoundException error) {
        Ln.w(error.getCause());
    } catch (ClassNotFoundException error) {
        Ln.w(error.getCause());
    }
}

有趣的事实:它不无 GET_META_DATA 标记工作,因为将始终返回为空如果不包括该标记。

fun fact: it doesn't work without the GET_META_DATA flag, as the metaData will always return as null if you don't include that tag.

最后的接触是调用此方法,可能会在的onCreate 您最初的活动的

The last touch is to call this method, likely in the onCreate of your initial Activity

@Override
protected void onCreate(Bundle icicle) {
    super.onCreate(icicle);

    // Anything else you want to do in the onCreate callback

    // Set up to use the appropriate Activities for the given device
    UIUtils.configureDeviceSpecificActivities(this);
}

现在你可以有活动 s表示是专为手机和平板电脑的时候,只是改变了布局,并可能包括多个片段 s是不充分的。

Now you can have Activitys that are specially designed for phones and tablets for the times when just changing the layout and maybe including more Fragments isn't sufficient.

注:最后弦乐=将class_name + info.packageName info.name; 可能是最后弦乐=将class_name info.name; 如果你看到一个警告。

NOTE: final String class_name = info.packageName + info.name; might have to be final String class_name = info.name; if you see a warning.

注(2):最后弦乐target_device = info.metaData.getString(target_device,).toLowerCase(); 应该是过去的API向后兼容性12。

NOTE(2): final String target_device = info.metaData.getString("target_device", "").toLowerCase(); should be for backward compatibility past API 12.

String target_device = info.metaData.getString("target_device");
if (target_device == null) break;
target_device = target_device.toLowerCase();

注(3): target_device.toLowerCase(); 使用默认的语言环境含蓄。使用 target_device.toLowerCase(Locale.US)代替。并提出在code以上的所有更改。

NOTE(3): target_device.toLowerCase(); uses the default locale implicitly. Use target_device.toLowerCase(Locale.US) instead. And made all changes in the code above.