Mobile Development 25 min read

How to Rapidly Convert an Android Phone App to a Tablet Version in Under 3 Months

This article details a step‑by‑step approach for transforming a modern Android phone application into a tablet‑optimized version within three months, covering UI redesign, activity‑to‑fragment conversion, multi‑process handling, task management, and practical code snippets for a robust Pad‑ification architecture.

Tencent TDS Service
Tencent TDS Service
Tencent TDS Service
How to Rapidly Convert an Android Phone App to a Tablet Version in Under 3 Months

How to achieve a fast Pad‑ification of a latest‑version Android app is described, from receiving a large‑scale phone app code to releasing its first tablet version in less than three months.

Project Background

The goal is to adapt the latest phone app (referred to as MyApp) for tablets and large‑screen phones, providing a better experience. Understanding the classic page composition of MyApp and the structural changes after Pad‑ification is the first step.

1. MyApp Classic Page Composition

Typical phone apps use a tab bar with tab content on the main screen, while secondary pages are displayed full‑screen. MyApp follows the same pattern. The left image shows a tab bar (area 1) with tab content (area 2); the right image shows a full‑screen detail page (area 3) opened from the tab content.

Most screens are implemented with Android Activity components; a few hundred activities are present, including Web and picture‑selection processes.

1. MyApp Pad‑ification Design Diagram

After Pad‑ification, the UI is divided into three regions that correspond to the phone’s regions 1, 2, 3. The tab bar moves to the left (region 1), the tab content to the middle (region 2), and the detail page is displayed in region 3 instead of full‑screen.

Exploration Process for Pad‑ifying the Phone App

Based on the classic composition and the new Pad layout, three solution candidates were explored.

Solution 1 – Shrink Activities into a Single Screen

Make the whole design diagram a main Activity (full‑screen) and display new activities (A) reduced in size within region 3.

A‑type Activity inherits Base Activity.

Adjust Base Activity window coordinates (x, width) to fit region 3.

Make A‑type Activity background transparent.

Repeat steps for any Activity opened from A.

Problems discovered:

Activity A remains visible when switching tabs.

All Activities share a single back‑stack, causing back‑key conflicts across tabs.

Solution 2 – Attach Activity Root View to Main Activity

When launching A‑type Activity, obtain its root view via LocalActivityManager and add it to an empty layout in region 3 of the main Activity.

Override startActivity in the main Activity.

Use LocalActivityManager to start A and get its Window object.

Add window.getDecorView() to the main Activity.

Override back‑logic to remove the attached view.

Issues found:

The LocalActivityManager retains a reference to A, preventing its release.

Extracted decorView loses the Activity lifecycle, result handling, and other features.

Solution 3 – Convert Activities to Fragments

Use a plugin‑like approach: wrap each Activity inside a lightweight Fragment that forwards lifecycle calls, without modifying the original Activity code.

Create BasePadActivity that overrides startActivity, instantiates the target Activity, and attaches it to a new MyFragment. MyFragment holds a reference to the Activity instance, calls its lifecycle methods, and uses the Activity’s view as the Fragment’s view.

All Activity‑derived classes inherit BasePadActivity, enabling rapid conversion.

Advantages: fast bulk conversion, preserved logic, and reuse of the main Activity’s context for resources.

Remaining problems:

Custom TitleBar disappears.

All Fragments share a single FragmentManager, causing back‑stack interference across tabs.

Some Activity behaviors (launch mode, onActivityResult, etc.) are not fully simulated.

Multi‑process Activities lose their separate process characteristics.

Final Pad‑ification Architecture

The chosen architecture combines the strengths of the previous attempts:

Convert main‑process Activities to Fragments while keeping their code unchanged.

Fragments simulate Activity behavior (finish, back, result, launch mode).

Use LocalActivityManager to give each tab an independent Fragment stack.

Keep multi‑process Activities unconverted and display them as transparent windows positioned in region 3, preserving their separate processes.

1. Activity‑to‑Fragment Conversion

public class BasePadActivity extends Activity {
    @Override
    public void startActivityForResult(Intent intent) {
        if (isFragment && !isNewProcessActivity()) {
            BasePadActivity activity = (BasePadActivity) newInstance(intent);
            activity.attachBaseContext(getBaseContext());
            activity.onCreate(intent.getExtras());
            activity.addMyFragment();
        }
    }
}

public class MyFragment extends Fragment {
    @Override
    public View onCreateView() {
        return getWindow().getDecorView();
    }
    @Override
    public void onResume() {
        super.onResume();
        BasePadActivity.this.onResume();
    }
    @Override
    public void onPause() {
        super.onPause();
        BasePadActivity.this.onPause();
    }
}

2. Simulating Activity Behaviour in Fragments

Finish:

public void finish() {
    if (bActivityToFragment) {
        removeTopFragment();
    }
}

Result handling:

private void removeTopFragment() {
    if (popBackStackImmediate()) {
        handleSetResult(requestCode, false);
    }
}
private void handleSetResult(int requestCode) {
    topFragment.onActivityResult(requestCode, resultCode, data);
}

Back press:

public void onBackPressed() {
    if (isActivityForFragment()) {
        if (!handleFragmentBackEvent()) {
            finishTopFragment();
        }
    }
}

Launch mode detection:

public boolean hasFlagClearTop(int flags) {
    return (flags & Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0;
}
public boolean hasFlagNewTask(int flags) {
    return (flags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0;
}

3. Custom TitleBar in Fragments

Override getWindow() to return a custom Window4FragmentTitle that inflates the custom title layout into the Fragment’s decor view.

public Window getWindow() {
    if (customWindow == null) {
        customWindow = new Window4FragmentTitle(mContext);
    }
    return customWindow;
}

public class Window4FragmentTitle extends Window {
    @Override
    public void setContentView(View view, LayoutParams params) {
        if (mContentParent == null) installDecor();
        mContentParent.addView(view, params);
    }
    @Override
    public void setFeatureInt(int featureId, int value) {
        if (featureId != FEATURE_CUSTOM_TITLE) return;
        FrameLayout titleContainer = (FrameLayout) findViewById(android.R.id.title);
        if (titleContainer != null) {
            mLayoutInflater.inflate(value, titleContainer);
        }
    }
}

4. Independent Fragment Stacks per Tab

Each tab hosts its own Activity via LocalActivityManager, and each of those Activities manages a separate FragmentManager, ensuring isolation.

addFrame(Tab1Content.class, mTabs[1]);
addFrame(Tab2Content.class, mTabs[2]);

public void addFrame() {
    mTabHost.setup(getLocalActivityManager());
    TabSpec tabSpec = mTabHost.newTabSpec("").setIndicator(tab).setContent(new Intent(this, clz));
    mTabHost.addTab(tabSpec);
}

5. Multi‑Task Split‑Screen for Multi‑Process Activities

Multi‑process Activities remain transparent and are positioned in region 3 using layout parameters, while the left region continues to receive touch events (via FLAG_NOT_TOUCH_MODAL). Different tabs assign distinct taskAffinity values, creating separate tasks with independent back‑stacks.

<activity android:name="BrowserActivity1" android:process=":web" android:taskAffinity="com.tab1.BrowserActivity1" android:theme="@style/Default.Transparent" />
<activity android:name="BrowserActivity2" android:process=":web" android:taskAffinity="com.tab2.BrowserActivity2" android:theme="@style/Default.Transparent" />

When a web page is opened, the current tab index determines which activity (with the matching taskAffinity) is launched. Tab switches broadcast an intent that moves the corresponding task to front or back.

public void onTabSelected(int curTabIndex) {
    Intent i = new Intent("action");
    i.putExtra("cur_Tab_Id", curTabIndex);
    sendBroadcast(i);
}

public void onReceive(Context context, Intent intent) {
    int tab = intent.getIntExtra(CUR_TAB_ID, -1);
    if (tabIndex >= 0 && tabIndex == tab) {
        moveTaskToFront(mActivity.getTaskId());
    } else {
        moveTaskToBack();
    }
}

Summary

By applying the described architecture, MyApp’s Pad version was launched quickly and has remained stable through multiple iterations. The approach allows developers to modify pages without worrying whether they are backed by an Activity or a Fragment, preserving existing behavior while delivering a tablet‑optimized experience.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

task managementAndroidmulti-processUI architectureActivity to FragmentTablet Development
Tencent TDS Service
Written by

Tencent TDS Service

TDS Service offers client and web front‑end developers and operators an intelligent low‑code platform, cross‑platform development framework, universal release platform, runtime container engine, monitoring and analysis platform, and a security‑privacy compliance suite.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.